Python 如何将非重叠数据帧矢量化为重叠移位数据帧?

Python 如何将非重叠数据帧矢量化为重叠移位数据帧?,python,pandas,dataframe,vectorization,shift,Python,Pandas,Dataframe,Vectorization,Shift,我想将常规数据帧转换为具有重叠和移位的多索引数据帧 例如,输入数据帧类似于以下示例代码: import pandas as pd import numpy as np df = pd.DataFrame(data=np.arange(0, 12).reshape(-1, 2), columns=['d1', 'd2'], dtype=float) df.index.name = 'idx' print(df) 输出: d1 d2 idx 0

我想将常规数据帧转换为具有重叠和移位的多索引数据帧

例如,输入数据帧类似于以下示例代码:

import pandas as pd
import numpy as np
df = pd.DataFrame(data=np.arange(0, 12).reshape(-1, 2), columns=['d1', 'd2'], dtype=float)
df.index.name = 'idx'
print(df)
输出:

       d1    d2
idx            
0     0.0   1.0
1     2.0   3.0
2     4.0   5.0
3     6.0   7.0
4     8.0   9.0
5    10.0  11.0
我想要输出的是:按批次重叠,每次移动一行(添加列
batchid
来标记每个移动),如下所示(batchsize=4):

我目前的工作: 我可以让它与迭代一起工作,并将它们结合在一起。但这需要很多时间

batchsize = 4
ds, ids = [], []
idx = df.index.values
for bi in range(int(len(df) - batchsize + 1)):
    ids.append(idx[bi:bi+batchsize])
for k, idx in enumerate(ids):
    di = df.loc[pd.IndexSlice[idx], :].copy()
    di['batchid'] = k
    ds.append(di)
res = pd.concat(ds).fillna(0)
res.set_index('batchid', inplace=True, append=True)
有没有办法矢量化和加速这个过程


谢谢。

您可以通过
pd.concat
iloc
中的列表理解,使用
i
作为在
范围内迭代的变量来完成此操作。这应该更快:

batchsize = 4
df = (pd.concat([df.iloc[i:batchsize+i].assign(batchid=i) 
                 for i in range(df.shape[0] - batchsize + 1)])
      .set_index(['batchid'], append=True))
df
Out[1]: 
               d1    d2
idx batchid            
0   0         0.0   1.0
1   0         2.0   3.0
2   0         4.0   5.0
3   0         6.0   7.0
1   1         2.0   3.0
2   1         4.0   5.0
3   1         6.0   7.0
4   1         8.0   9.0
2   2         4.0   5.0
3   2         6.0   7.0
4   2         8.0   9.0
5   2        10.0  11.0

首先,我们创建一个“掩码”,它将告诉我们哪些元素进入哪个批次id

nrows = len(df)
batchsize = 4
mask_columns = {i:np.pad([1]*batchsize,(i,nrows-batchsize-i)) for i in range(nrows-batchsize+1)}
mask_df = pd.DataFrame(mask_columns)
df = df.join(mask_df)
这将向df添加几列:


  idx    d1    d2    0    1    2
-----  ----  ----  ---  ---  ---
    0     0     1    1    0    0
    1     2     3    1    1    0
    2     4     5    1    1    1
    3     6     7    1    1    1
    4     8     9    0    1    1
    5    10    11    0    0    1
这现在看起来像一个带有“假人”的df,我们需要“反转”假人:

df2 = df.set_index(['d1','d2'], drop=True)
df2[df2==1].stack().reset_index().drop(0,1).sort_values('level_2').rename(columns = {'level_2':'batchid'})
产生

      d1    d2    batchid
--  ----  ----  ---------
 0     0     1          0
 1     2     3          0
 3     4     5          0
 6     6     7          0
 2     2     3          1
 4     4     5          1
 7     6     7          1
 9     8     9          1
 5     4     5          2
 8     6     7          2
10     8     9          2
11    10    11          2

谢谢你,大卫!它更快。我只是测试你的解决方案。它加速约40%的速度。
      d1    d2    batchid
--  ----  ----  ---------
 0     0     1          0
 1     2     3          0
 3     4     5          0
 6     6     7          0
 2     2     3          1
 4     4     5          1
 7     6     7          1
 9     8     9          1
 5     4     5          2
 8     6     7          2
10     8     9          2
11    10    11          2