2012-10-24 3 views
11

Sto provando a trasformare DataFrame, in modo tale che alcune delle righe vengano replicate un determinato numero di volte. Ad esempio:panda: applica la funzione a DataFrame che può restituire più righe

df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count':[1,0,2]}) 

    class count 
0  A  1 
1  B  0 
2  C  2 

devono essere trasformati in:

class 
0  A 
1  C 
2  C 

Questa è l'inverso di aggregazione con funzione di conteggio. C'è un modo semplice per ottenerlo nei panda (senza usare loop o liste di comprensione)?

Una possibilità potrebbe essere quella di consentire la funzione DataFrame.applymap restituire più righe (akin apply metodo GroupBy). Tuttavia, non credo sia possibile ora nei panda.

+0

Ho anche in mente una funzione generale che consentirà di restituire più righe, una o zero in base ai valori nella colonna 'count'. – btel

+0

Se venite a questa domanda nel 2017+, controllate la mia risposta per una soluzione più efficiente e diretta. –

risposta

17

È possibile utilizzare groupby:

def f(group): 
    row = group.irow(0) 
    return DataFrame({'class': [row['class']] * row['count']}) 
df.groupby('class', group_keys=False).apply(f) 

in modo da ottenere

In [25]: df.groupby('class', group_keys=False).apply(f) 
Out[25]: 
    class 
0  A 
0  C 
1  C 

È possibile correggere l'indice del risultato come più vi piace

+0

Questo risolve il mio problema! Grazie Wes. – btel

+1

Buona risposta! Se ho dozzine di altre colonne, c'è un modo semplice per preservare quelle colonne nel risultato di 'f' diverso dalla digitarle tutte esplicitamente? –

1
repeated_items = [list(row[1]*row[2]) for row in df.itertuples()] 

creerà un elenco nidificato:

[['A'], [], ['C', 'C']] 

che è quindi possibile iterare con list comprehension per creare una nuova cornice di dati:

new_df = pd.DataFrame({"class":[j for i in repeated_items for j in i]}) 

Naturalmente, si può fare in una sola riga se lo desideri:

new_df = pd.DataFrame({"class":[j for i in [list(row[1]*row[2]) for row in df.itertuples()] for j in i]}) 
3

So che questa è una vecchia questione, ma io stavo avendo problemi nel far funzionare la risposta di Wes per più colonne nel dataframe, quindi ho reso il suo codice un po 'più generico. Ho pensato di condividere nel caso in cui qualcun altro si imbattesse in questa domanda con lo stesso problema.

Semplicemente si specifica in quale colonna sono presenti i conteggi e in cambio si ottiene un dataframe espanso.

import pandas as pd 
df = pd.DataFrame({'class 1': ['A','B','C','A'], 
        'class 2': [ 1, 2, 3, 1], 
        'count': [ 3, 3, 3, 1]}) 
print df,"\n" 

def f(group, *args): 
    row = group.irow(0) 
    Dict = {} 
    row_dict = row.to_dict() 
    for item in row_dict: Dict[item] = [row[item]] * row[args[0]] 
    return pd.DataFrame(Dict) 

def ExpandRows(df,WeightsColumnName): 
    df_expand = df.groupby(df.columns.tolist(), group_keys=False).apply(f,WeightsColumnName).reset_index(drop=True) 
    return df_expand 


df_expanded = ExpandRows(df,'count') 
print df_expanded 

Returns:

class 1 class 2 count 
0  A  1  3 
1  B  2  3 
2  C  3  3 
3  A  1  1 

    class 1 class 2 count 
0  A  1  1 
1  A  1  3 
2  A  1  3 
3  A  1  3 
4  B  2  3 
5  B  2  3 
6  B  2  3 
7  C  3  3 
8  C  3  3 
9  C  3  3 

Per quanto riguarda la velocità, la mia df base è 10 colonne di ~ 6k righe e quando espanso è ~ 100.000 righe prende ~ 7 secondi. Non sono sicuro in questo caso se il raggruppamento è necessario o saggio poiché sta prendendo tutte le colonne in una forma di gruppo, ma hey qualunque sia solo 7 secondi.

0

Questa domanda è molto vecchia e le risposte non riflettono le funzionalità moderne dei panda. È possibile utilizzare iterrows per eseguire il loop su ogni riga e quindi utilizzare il costruttore DataFrame per creare nuovi DataFrames con il numero corretto di righe. Infine, utilizzare pd.concat per concatenare tutte le righe insieme.

pd.concat([pd.DataFrame(data=[row], index=range(row['count'])) 
      for _, row in df.iterrows()], ignore_index=True) 

    class count 
0  A  1 
1  C  2 
2  C  2 

Questo ha il vantaggio di lavorare con qualsiasi dimensione DataFrame.