2017-08-22 5 views
1

Désolé si le titre n'est pas assez clair. Laissez-moi vous expliquer ce que je veux accomplir.Créer de nouvelles colonnes basées sur des valeurs distinctes et les compter

J'ai ce Data-Frame, appelons-le df. Je souhaite créer un nouveau référentiel de données basé sur les valeurs du référentiel de données existant. Premièrement, je voudrais trouver une somme totale de id distinct en df. Ex. id A a 3 entrées, B a 2 entrées, etc. Ensuite, créez une nouvelle trame de données.

Pour notre nouvelle trame de données, nous allons l'appeler df_new

id | count 
A 3 
B 2 
C 2 
D 4 

Ensuite, je voudrais créer une nouvelle colonne en fonction des valeurs df [ « Zone »], pour cet exemple, df [ » Area '] contient 3 valeurs distinctes (une, deux, trois). Je voudrais compter le nombre de fois qu'un identifiant a été dans quelle zone. Par exemple, l'identifiant A a été dans la zone un deux fois, une fois dans la zone deux et zéro dans la zone trois. Ensuite, je vais ajouter ces valeurs dans une nouvelle colonne appelée un, deux et trois.

df_new:

id | count | one | two | three 
A 3  2  1  0 
B 2  2  0  0 
C 2  1  1  0 
D 4  2  1  1 

J'ai développé mon propre code qui produit df_new, mais je crois que Pandas a une meilleure fonction pour effectuer ce type d'extraction de données. Voici mon code.

#Read the data 
df = pd.read_csv('test_data.csv', sep = ',') 
df.columns = ['id', 'Area'] #Rename 
# Count a total number of Area by Id 
df_new = pd.DataFrame({'count' : df.groupby("id")["Area"].count()}) 
# Reset index 
df_new = df_new.reset_index() 
#For loop for counting and creating a new column for areas in df['Area'] 
for i in xrange(0, len(df)): 
    #Get the id 
    idx = df['id'][i] 
    #Get the areaname 
    area_name = str(df["Area"][i]) 
    #Retrieve the index of a particular id 
    current_index = df_new.loc[df_new['id'] == idx, ].index[0] 
    #If area name exists in a column 
    if area_name in df_new.columns: 
     #Then +1 at the Location of the idx (Index) 
     df_new[area_name][current_index] += 1 
    #If not exists in the columns 
    elif area_name not in df_new.columns: 
     #Create an empty one with zeros 
     df_new[area_name] = 0 
     #Then +1 at the location of the idx (Index) 
     df_new[area_name][current_index] += 1 

Le code est long et difficile à lire. Il souffre également de l'avertissement "Une valeur essaie d'être définie sur une copie d'une tranche à partir d'un DataFrame". Je voudrais apprendre plus sur comment écrire ceci efficacement.

Merci

Répondre

0

Vous pouvez utiliser df.groupby.count pour la première partie et pd.crosstab pour le second. Ensuite, utilisez pd.concat à se joindre em:

In [1246]: pd.concat([df.groupby('id').count().rename(columns={'Area' : 'count'}),\ 
         pd.crosstab(df.id, df.Area)], 1) 
Out[1246]: 
    count one three two 
id       
A  3 2  0 1 
B  2 2  0 0 
C  2 1  0 1 
D  4 2  1 1 

est ici la première partie en utilisant df.groupby:

df.groupby('id').count().rename(columns={'Area' : 'count'}) 

    count 
id  
A  3 
B  2 
C  2 
D  4 

est ici la deuxième partie avec pd.crosstab:

pd.crosstab(df.id, df.Area) 

Area one three two 
id     
A  2  0 1 
B  2  0 0 
C  1  0 1 
D  2  1 1 

Pour la deuxième partie , vous pouvez également utiliser pd.get_dummies et faire un produit scalaire:

(pd.get_dummies(df.id).T).dot(pd.get_dummies(df.Area)) 

    one three two 
A 2  0 1 
B 2  0 0 
C 1  0 1 
D 2  1 1 
+1

Oh ouah, c'est incroyable. Merci, je vais cocher votre réponse quand elle sera disponible dans 7 minutes. –

+0

Encore une question, est-il possible de générer un nombre binaire au lieu d'un nombre en utilisant l'onglet croisé? Au lieu de compter, seulement 1 pour oui si un certain ID a été à cette zone et 0 pour un certain ID n'a jamais été là? –

+0

@ Niche.P D'accord, je l'ai. C'est: 'pd.crosstab (df.id, df.Area) .astype (bool) .astype (int)' –