Replica le righe x volte nel dataframe - migliora le prestazioni [duplicato]

Aug 24 2020

Sto cercando la soluzione più efficiente per replicare le righe di dataframe. Ogni riga deve essere replicata x volte, dove x è univoco per ogni riga.

Diciamo che questo è il mio dataframe dato:

| id | count |
|----|-------|
| a  | 1     |
| b  | 2     |
| c  | 5     |

Il dataframe come risultato dovrebbe assomigliare a questo, in cui ogni riga è stata replicata dall'importo indicato nella colonna "count":

| id | count |
|----|-------|
| a  | 1     |
| b  | 2     |
| b  | 2     |
| c  | 5     |
| c  | 5     |
| c  | 5     |
| c  | 5     |
| c  | 5     |

Un approccio molto semplice sarebbe il looping sul dataframe e l'aggiunta della riga x volte in questo modo:

data = {'id': ['a', 'b', 'c'], 'count': [1, 2, 5]}
df = pd.DataFrame(data=data)

for index, row in df.iterrows():
    for x in range(row['count']-1):
        df = df.append(pd.Series(row, index=df.columns), ignore_index=True)

df = df.sort_values(by=['id'])
df = df.reset_index(drop=True)

df

Sebbene funzioni per piccoli frame di dati, non è molto efficiente per frame di dati di grandi dimensioni con migliaia di righe. Poiché ogni riga deve essere replicata fino a 200 volte, il dataframe finale può contenere milioni di righe.

Ho già letto di pandas/numpy vectorization, ma sfortunatamente non ho idea se (e come) possa essere d'aiuto in questo caso in cui devo aggiungere molte righe al dataframe.

Qualche suggerimento su come migliorare le prestazioni?

Risposte

4 jezrael Aug 24 2020 at 20:10

Usa Index.repeatse valori di indice univoci e poi passa a DataFrame.loc:

df1 = df.loc[df.index.repeat(df['count'])].reset_index(drop=True)
print (df1)
  id  count
0  a      1
1  b      2
2  b      2
3  c      5
4  c      5
5  c      5
6  c      5
7  c      5

Se possibile alcuni duplicati nei valori di indice è possibile utilizzare numpy.repeate DataFrame.iloc:

print (df)
  id  count
0  a      1
1  b      2
1  c      5

df1 = df.iloc[np.repeat(np.arange(len(df.index)), df['count'])].reset_index(drop=True)
print (df1)
  id  count
0  a      1
1  b      2
2  b      2
3  c      5
4  c      5
5  c      5
6  c      5
7  c      5
1 sammywemmy Aug 24 2020 at 20:14

Potresti reindicizzare con la countcolonna:

df.reindex(df.index.repeat(df["count"])).reset_index(drop=True)
DarshShukla Aug 24 2020 at 21:49
In [1]: import numpy as np 
   ...: import pandas as pd                                                                         

In [2]: data = {'id':list(map(chr, range(97, 123))), 'count': pd.Series(np.random.randint(0,500,size
   ...: =26))}                                                                                      

In [3]: df = pd.DataFrame(data)                                                                     

In [4]: df.head()                                                                                   
Out[4]: 
  id  count
0  a    145
1  b    297
2  c     46
3  d    493
4  e     46

In [5]: df_replicate = pd.DataFrame(np.repeat(df.values, df['count'], axis=0),columns=df.columns)   

In [6]: df_replicate.head()                                                                         
Out[6]: 
  id count
0  a   145
1  a   145
2  a   145
3  a   145
4  a   145