2010-05-13 3 views
0

J'ai un script qui contient deux classes. (Je supprime évidemment beaucoup de choses que je ne crois pas pertinentes à l'erreur que je traite.) La tâche finale est de créer un arbre de décision, comme je l'ai mentionné dans la question this. Malheureusement, je reçois une boucle infinie, et j'ai de la difficulté à identifier pourquoi. J'ai identifié la ligne de code qui déraille, mais j'aurais pensé que l'itérateur et la liste que j'ajouterais seraient des objets différents. Y a-t-il un effet secondaire de la fonctionnalité .append de la liste dont je ne suis pas au courant? Ou est-ce que je fais une autre erreur évidente?Boucle infinie lors de l'ajout d'une ligne à une liste dans une classe dans python3

class Dataset: 
    individuals = [] #Becomes a list of dictionaries, in which each dictionary is a row from the CSV with the headers as keys 
    def field_set(self): #Returns a list of the fields in individuals[] that can be used to split the data (i.e. have more than one value amongst the individuals 
    def classified(self, predicted_value): #Returns True if all the individuals have the same value for predicted_value 
    def fields_exhausted(self, predicted_value): #Returns True if all the individuals are identical except for predicted_value 
    def lowest_entropy_value(self, predicted_value): #Returns the field that will reduce <a href="http://en.wikipedia.org/wiki/Entropy_%28information_theory%29">entropy</a> the most 
    def __init__(self, individuals=[]): 

et

class Node: 
    ds = Dataset() #The data that is associated with this Node 
    links = [] #List of Nodes, the offspring Nodes of this node 
    level = 0 #Tree depth of this Node 
    split_value = '' #Field used to split out this Node from the parent node 
    node_value = '' #Value used to split out this Node from the parent Node 

    def split_dataset(self, split_value): #Splits the dataset into a series of smaller datasets, each of which has a unique value for split_value. Then creates subnodes to store these datasets. 
     fields = [] #List of options for split_value amongst the individuals 
     datasets = {} #Dictionary of Datasets, each one with a value from fields[] as its key 
     for field in self.ds.field_set()[split_value]: #Populates the keys of fields[] 
      fields.append(field) 
      datasets[field] = Dataset() 
     for i in self.ds.individuals: #Adds individuals to the datasets.dataset that matches their result for split_value 
      datasets[i[split_value]].individuals.append(i) #<---Causes an infinite loop on the second hit 
     for field in fields: #Creates subnodes from each of the datasets.Dataset options 
      self.add_subnode(datasets[field],split_value,field) 

    def add_subnode(self, dataset, split_value='', node_value=''): 
    def __init__(self, level, dataset=Dataset()): 

Mon code d'initialisation est actuellement:

if __name__ == '__main__': 
    filename = (sys.argv[1]) #Takes in a CSV file 
    predicted_value = "# class" #Identifies the field from the CSV file that should be predicted 
    base_dataset = parse_csv(filename) #Turns the CSV file into a list of lists 
    parsed_dataset = individual_list(base_dataset) #Turns the list of lists into a list of dictionaries 
    root = Node(0, Dataset(parsed_dataset)) #Creates a root node, passing it the full dataset 
    root.split_dataset(root.ds.lowest_entropy_value(predicted_value)) #Performs the first split, creating multiple subnodes 
    n = root.links[0] 
    n.split_dataset(n.ds.lowest_entropy_value(predicted_value)) #Attempts to split the first subnode. 

Répondre

4
class Dataset: 
    individuals = [] 

suspicieux. À moins que vous souhaitiez avoir une liste de membres statique partagée par toutes les instances de Dataset, vous ne devriez pas faire cela. Si vous définissez self.individuals= something dans __init__, vous n'avez pas besoin de définir individuals ici aussi.

def __init__(self, individuals=[]): 

Toujours suspect. Affectez-vous l'argument individuals à self.individuals? Si tel est le cas, vous attribuez la même liste individuals, créée au moment de la définition de la fonction, à chaque Dataset créé avec un argument par défaut. Ajouter un article à une liste de Dataset et tous les autres créés sans un argument explicite individuals obtiendront également cet objet.

De même:

class Node: 
    def __init__(self, level, dataset=Dataset()): 

Tous les Node s créés sans argument dataset explicite recevront le même défaut Dataset instance exacte.

Ceci est le mutable default argument problem et le type d'itérations destructrices qu'il produirait semblerait très probablement causer votre boucle infinie.

+0

+1 Bonne réponse. –

4

Je soupçonne que vous apposent à la même liste que vous itérez l'amenant à augmenter la taille avant l'itérateur peut atteindre la fin. Essayez itérer sur une copie de la liste à la place:

for i in list(self.ds.individuals): 
    datasets[i[split_value]].individuals.append(i) 
+0

Est-ce que Python 3 a toujours l'opérateur de tranche? IE pour moi dans self.ds.individuals [:]: other_code ? – mcpeterson

+0

@McPeterson, Les tranches fonctionnent toujours en Python3 –

Questions connexes