使用Pandas DataFrame,通过复制先前DataFrame的行n次并更改日期来创建新的DataFrame。

5
我有一个包含约9K行和57列的数据框,称为“df”。
我需要创建一个新的数据框:“df_final”,对于“df”的每一行,我需要复制每一行“x”次,并依次递增每一行中的日期,“x”次。尽管我可以完成几次迭代,但当我对“df”的全长(即len(df))进行操作时,这个循环时间太长了(>3小时),我不得不取消它。我从未看到过它的结束。以下是当前的代码:
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

' df'的前两行循环的结果如下:
第一、二行df: enter image description here 期望的结果: enter image description here 是否有其他方法来获得所需的输出。似乎pandas不太擅长处理循环。在VBA excel中,同样的循环需要大约3/4分钟...我正在尝试将当前在excel中的过程更改为python,但是,如果无法使其正常工作,我想我会坚持旧方法...
3个回答

4
使用repeatcumcount
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

细节说明
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

真的很棒的解决方案。 - Bharath M Shetty

1

让我们使用这个玩具数据框:

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

它看起来像这样:

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

然后:

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

这将给你重复:
        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

现在你只需要递增日期:
inc = np.tile(np.arange(x), len(df)) # 0,1,2,0,1,2
df_final.date += pd.to_timedelta(inc, 'D')

你会得到:

        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

1
这是一个解决方案。
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

然后。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接