2011-09-28 1 views
9

J'essaie de sous-échantillonner des lignes d'un DataFrame en fonction d'un regroupement. Voici un exemple. Dis-je définir les données suivantes:En utilisant des pandas, comment sous-échantillonner efficacement un grand DataFrame par groupe?

from pandas import * 
df = DataFrame({'group1' : ["a","b","a","a","b","c","c","c","c", 
          "c","a","a","a","b","b","b","b"], 
       'group2' : [1,2,3,4,1,3,5,6,5,4,1,2,3,4,3,2,1], 
       'value' : ["apple","pear","orange","apple", 
          "banana","durian","lemon","lime", 
          "raspberry","durian","peach","nectarine", 
          "banana","lemon","guava","blackberry","grape"]}) 

Si le groupe I par group1 et group2, le nombre de lignes dans chaque groupe est ici:

In [190]: df.groupby(['group1','group2'])['value'].agg({'count':len}) 
Out[190]: 
     count 
a 1 2  
    2 1  
    3 2  
    4 1  
b 1 2  
    2 2  
    3 1  
    4 1  
c 3 1  
    4 1  
    5 2  
    6 1  

(S'il existe un moyen encore plus concis calculer cela, s'il vous plaît dire.)

Je veux maintenant construire un DataFrame qui a une rangée sélectionnée au hasard de chaque groupe. Ma proposition est de le faire comme ça:

In [215]: from random import choice 
In [216]: grouped = df.groupby(['group1','group2']) 
In [217]: subsampled = grouped.apply(lambda x: df.reindex(index=[choice(range(len(x)))])) 
In [218]: subsampled.index = range(len(subsampled)) 
In [219]: subsampled 
Out[219]: 
    group1 group2 value 
0 b  2  pear 
1 a  1  apple 
2 b  2  pear 
3 a  1  apple 
4 a  1  apple 
5 a  1  apple 
6 a  1  apple 
7 a  1  apple 
8 a  1  apple 
9 a  1  apple 
10 a  1  apple 
11 a  1  apple 

qui fonctionne. Cependant, mes données réelles ont environ 2,5 millions de lignes et 12 colonnes. Si je fais cela de façon sale en construisant mes propres structures de données, je peux terminer cette opération en quelques secondes. Cependant, mon implémentation ci-dessus ne se termine pas dans les 30 minutes (et ne semble pas limitée en mémoire). Comme une note latérale, quand j'ai essayé d'implémenter ceci dans R, j'ai d'abord essayé plyr, qui n'a pas non plus fini dans une quantité raisonnable de temps; cependant, une solution utilisant data.table s'est terminée très rapidement.

Comment puis-je faire en sorte que cela fonctionne rapidement avec pandas? Je veux aimer ce paquet, alors aidez svp!

Répondre

8

J'ai testé avec apply, il semble que quand il y a beaucoup de sous-groupes, c'est très lent. les groupes d'attributs de feux groupés est un dict, vous pouvez indexer de choix directement de celui-ci:

subsampled = df.ix[(choice(x) for x in grouped.groups.itervalues())] 

EDIT: Comme la version de pandas géants 0.18.1, itervalues ne fonctionne plus sur les objets GroupBy - vous pouvez simplement utiliser .values:

subsampled = df.ix[(choice(x) for x in grouped.groups.values())] 
+3

J'ai répondu sur la liste de diffusion pystatsmodels à ce sujet. Je suis venu avec la même solution que vous avez suggéré - étant l'auteur du paquet je ne sais pas d'une meilleure façon =) –

+0

@wesm, J'étais sur le point de poster votre réponse ici aussi bien. Merci tout le monde! –

Questions connexes