2017-09-23 1 views
3

J'ai une dataframe avec environ 9k lignes et 57 cols, c'est 'df'.pandas dataframe créer une nouvelle dataframe en dupliquant n fois les lignes de la frameframe précédente et changer la date

Je dois avoir une nouvelle base de données: 'df_final' - pour chaque ligne de 'df' je dois répliquer chaque ligne 'x' fois et augmenter le jour dans chaque rangée un par un, aussi 'x' fois . Alors que je peux le faire pour quelques itérations, quand je le fais pour toute la longueur de 'df' 'len (df)' la boucle prend tellement de temps (> 3 heures) que je devais l'annuler. Je n'ai jamais vu la fin de celui-ci. Voici le code actuel:

df.shape 
output: (9454, 57) 

df_int = df[0:0] 
df_final = df_int[0:0] 
range_df = len(df) 
for x in range(0,2): 
    df_int = df.iloc[0+x:x+1] 
    if abs(df_int.iat[-1,3]) > 0: 
     df_int = pd.concat([df_int]*abs(df_int.iat[-1,3]), ignore_index=True) 
     for i in range(1, abs(df_int.iat[-1,3])): 
      df_int['Consumption Date'][i] = df_int['Consumption Date'][i-1] + datetime.timedelta(days = 1) 
      i += 1 
     df_final = df_final.append(df_int, ignore_index=True) 
    x += 1 

Le résultat des boucles pour les deux premières lignes de 'df' est ci-dessous.

deux premières rangées de df: enter image description here

résultat souhaité: enter image description here

Y at-il une autre façon de se rendre à la sortie désirée. Il semble que les pandas ne se débrouillent pas très bien avec les boucles. Dans VBA excel, la même boucle prend environ 3/4 minutes ... J'essaie de changer un processus qui est actuellement en excel en python, cependant, s'il n'y a aucun moyen de faire fonctionner ce système, je suppose que je m'en tiendrai aux vieilles méthodes. ..

Répondre

2

Utilisez repeat et cumcount

In [2972]: dff = df.loc[df.index.repeat(3)] 

In [2973]: dff 
Out[2973]: 
     date name 
0 2017-05-03 bob 
0 2017-05-03 bob 
0 2017-05-03 bob 
1 2017-06-13 sally 
1 2017-06-13 sally 
1 2017-06-13 sally 

In [2974]: dff.loc[:, 'date'] += pd.to_timedelta(dff.groupby(level=0).cumcount(), 'D') 

In [2975]: dff 
Out[2975]: 
     date name 
0 2017-05-03 bob 
0 2017-05-04 bob 
0 2017-05-05 bob 
1 2017-06-13 sally 
1 2017-06-14 sally 
1 2017-06-15 sally 

Détails

In [2976]: df 
Out[2976]: 
     date name 
0 2017-05-03 bob 
1 2017-06-13 sally 

In [2977]: dff.groupby(level=0).cumcount() 
Out[2977]: 
0 0 
0 1 
0 2 
1 0 
1 1 
1 2 
dtype: int64 
+0

sol – Dark

+0

vraiment gentil merci beaucoup! cela va comme un gant! :) – dapaz

1

utilisons cette dataframe jouet:

df = pd.DataFrame({ 
    'date': pd.to_datetime(['2017-05-03', '2017-06-13']), 
    'name': ['bob', 'sally'], 
}) 

Il ressemble à ceci:

 date name 
0 2017-05-03 bob 
1 2017-06-13 sally 

Puis:

x = 3 # repeat count 
ind = np.repeat(np.arange(len(df)), x) # 0,0,0,1,1,1 
df_final = df.iloc[ind].copy() 

Cela vous donne les répétitions:

 date name 
0 2017-05-03 bob 
0 2017-05-03 bob 
0 2017-05-03 bob 
1 2017-06-13 sally 
1 2017-06-13 sally 
1 2017-06-13 sally 

Maintenant, il vous suffit d'incrémenter les dates:

inc = np.tile(np.arange(x), len(df)) # 0,1,2,0,1,2 
df_final.date += pd.to_timedelta(inc, 'D') 

Et vous obtenez:

 date name 
0 2017-05-03 bob 
0 2017-05-04 bob 
0 2017-05-05 bob 
1 2017-06-13 sally 
1 2017-06-14 sally 
1 2017-06-15 sally 
+0

merci pour la réponse – dapaz

0

Voici une solution

df1=df.reset_index().set_index('date').groupby('index').\ 
    apply(lambda x :x.reindex(pd.date_range(start=x.index[0],periods=3,freq='D'))).ffill() 
df1 
Out[202]: 
        index name 
index       
0  2017-05-03 0.0 bob 
     2017-05-04 0.0 bob 
     2017-05-05 0.0 bob 
1  2017-06-13 1.0 sally 
     2017-06-14 1.0 sally 
     2017-06-15 1.0 sally 

Puis

df1.drop('index',1).reset_index().rename(columns={'level_1':'date'}).drop('index',1) 

Out[212]: 
     date name 
0 2017-05-03 bob 
1 2017-05-04 bob 
2 2017-05-05 bob 
3 2017-06-13 sally 
4 2017-06-14 sally 
5 2017-06-15 sally