Python 使用Pandas dataframe(列操作)提高我的代码的性能

Python 使用Pandas dataframe(列操作)提高我的代码的性能,python,pandas,dataframe,bigdata,Python,Pandas,Dataframe,Bigdata,我正在学习Pandas dataframe和一个与性能优化相关的问题。由于我的速度慢,而且是新手,所以我的代码似乎编写不正确,即使输出是正确的,但性能也很差 问题:我有0和1的位模式。我必须找到1的步幅(为我的分析计算contiguos 1)。我的数据帧是200000列x200行。现在速度非常慢,正在寻找一种更好的方法来完成完整的解决方案,或者用向量操作替换所有列的“for-loop”。例如: Input: 1,1,1,1,0,0,1,1,0,0,1,1,1 Output: 4,4,4,4,

我正在学习Pandas dataframe和一个与性能优化相关的问题。由于我的速度慢,而且是新手,所以我的代码似乎编写不正确,即使输出是正确的,但性能也很差

问题:我有0和1的位模式。我必须找到1的步幅(为我的分析计算contiguos 1)。我的数据帧是200000列x200行。现在速度非常慢,正在寻找一种更好的方法来完成完整的解决方案,或者用向量操作替换所有列的“for-loop”。例如:

Input:  1,1,1,1,0,0,1,1,0,0,1,1,1 
Output: 4,4,4,4,0,0,2,2,0,0,3,3,3 (1 is replaced with the stride for 1)
我已经提取了一个示例代码以供审查。如果有人能帮上忙,我将不胜感激

start_time = timeit.default_timer()
# Small sample
AA = [1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0]
AB = [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0]
AC = [1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0]
AD = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
AE = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

df = pd.DataFrame({"A0": AA, "A1": AB, "A2": AB, "A3": AB, "A4": AB, "A5": AC, "A6": AD, "A7": AE, "A8": AE, "A9": AE})
# End of Debug Data Frame

df2=pd.DataFrame() # initialize to empty

print("Starting")
start_time = timeit.default_timer()
df1=pd.DataFrame(df != df.shift()).cumsum() # Operation-1: detects edges and increments at edge

print("Processing columns. Time=", timeit.default_timer() - start_time)
    
for c in df1.columns:
    df2[c] = df1.groupby(c)[c].transform('count') * df[c] # This takes maximum time as I am counting column by column

print("Done Processing columns. Time=", timeit.default_timer() - start_time)
对于我的数据帧(200000列x200行),“For循环”需要700秒

Starting
Processing columns. Time= 0.9377922620624304
Done Processing columns. Time= 701.7339988127351
Done generating data. Time= 702.0729111488909

这里有一个替代方案,在示例数据帧上,不确定速度上的差异是否显著,但应该在更大的数据帧上。其思想是沿行使用(一次针对每一列),将原始df用作布尔值,以
pd.NA
替换累计df中的值,其中df为1。然后,您需要玩一些
bfill
ffill
,以获得预期的结果

df_ = df.cumsum().mask(df.astype(bool)) # Removing pd.NaT helped
df2 = (df_.bfill() - df_.ffill().fillna(0)).fillna(0)

print(df2)
    A0  A1  A2  A3  A4  A5  A6  A7  A8  A9
0    1   0   0   0   0   2   0  10  10  10
1    0   8   8   8   8   2   1  10  10  10
2    0   8   8   8   8   0   0  10  10  10
3    2   8   8   8   8   2   1  10  10  10
4    2   8   8   8   8   2   0  10  10  10
5    0   8   8   8   8   0   1  10  10  10
6    0   8   8   8   8   0   0  10  10  10
7    0   8   8   8   8   0   1  10  10  10
8    1   8   8   8   8   1   0  10  10  10
9    0   0   0   0   0   0   1  10  10  10
10   1   1   1   1   1   1   0   0   0   0
11   0   0   0   0   0   0   1   0   0   0
12   5   5   5   5   5   5   0   0   0   0
13   5   5   5   5   5   5   1   0   0   0
14   5   5   5   5   5   5   0   0   0   0
15   5   5   5   5   5   5   1   0   0   0
16   5   5   5   5   5   5   0   0   0   0
17   0   0   0   0   0   0   1   0   0   0
18   0   0   0   0   0   0   0   0   0   0
19   0   0   0   0   0   0   0   0   0   0

非常感谢您的回复。它在较小的测试序列上测试得很好。当我移动到我的大型数据集时,即使超过一个小时,它也不会结束。我破坏了您在调试步骤中提供的解决方案,而“df_ufill().fillna(0)”将永远花费时间。有什么建议或替代方案吗?@Dsrivast我有点惊讶这部分这么长!据我所知,我唯一不经常使用的是前一行中的
pd.NA
。因此,试着只做
df_979;=df.cumsum().mask(df.astype(bool))
看看您是否仍然存在效率问题。然后您可能需要强制转换为最终整数result@Ben-这就成功了,我看到性能提高了12倍。非常感谢你的帮助。有人把我的问题降级了。我花了很多时间做研究和遵循指导方针。请帮助我了解如何改进我的问题。随着我的学习,我想继续提问,而不必承受太大的降级压力。@Dsrivast很高兴知道wihtout pd.NA效果更好,我将与pd.NA一起深入探讨这个性能问题。