2011-09-28 8 views
9

Sto provando a sottocampionare le righe di un DataFrame in base a un raggruppamento. Ecco un esempio. Dì che definisco i seguenti dati:Utilizzando i panda, come faccio a sottocampione di un DataFrame di grandi dimensioni per gruppo in modo efficiente?

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"]}) 

Se raggruppa per group1 e group2, allora il numero di righe in ogni gruppo è qui:

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  

(Se c'è un modo ancora più conciso calcolare, per favore, dire.)

Ora voglio costruire un DataFrame che ha una riga selezionata a caso da ciascun gruppo. La mia proposta è di farlo in questo modo:

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 

che funziona. Tuttavia, i miei dati reali hanno circa 2,5 milioni di righe e 12 colonne. Se faccio questo in modo sporco costruendo le mie strutture dati, posso completare questa operazione in pochi secondi. Tuttavia, la mia implementazione sopra non termina entro 30 minuti (e non sembra essere limitata in memoria). Come nota a margine, quando ho provato a implementarlo in R, ho provato per la prima volta a plyr, che non è terminato in un ragionevole lasso di tempo; tuttavia, una soluzione che utilizza data.table è terminata molto rapidamente.

Come ottengo che funzioni rapidamente con pandas? Voglio amare questo pacchetto, quindi per favore aiuto!

risposta

8

Ho provato con apply, sembra che quando ci sono molti sottogruppi, è molto lento. i gruppi attribuiscono di raggruppato è un dizionario, è possibile indicizzare scelta direttamente da esso:

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

EDIT: Come di panda versione 0.18.1, itervalues non funziona più su oggetti GroupBy - si può semplicemente utilizzare .values:

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

Ho risposto alla mailing list di pystatsmodels a riguardo. Mi è venuta in mente la stessa soluzione che hai suggerito-- essendo l'autore del pacchetto che non conosco in modo migliore =) –

+0

@ wesm, stavo proprio per pubblicare la tua risposta qui. Grazie a tutti! –