数据框提高列设置值的for循环速度

时间:2020-10-12 22:21:10

标签: python pandas dataframe

我有pandas的数据框(以pd导入pandas)

print(df)
        C1  C2
    0    0   0
    1    0   0
    2    1   0
    3    1   1
    4    1   1
    5    0   1
    6    0   0
    7    0   0
    8    0   0
    9    1   0
    10   1   1
    11   1   1
    12   0   1
    13   0   0

我想在上升沿之后在“ C3”中计数+1(当C1 = 1和C2 = 0时上升沿开始) 我尝试过iterrow()

count=1
df['C3'] = 0
for index, row in df.iterrows():
        if (row.C1 == 1) and (row.C2 == 0):
               count += 1 
               df.at[index, 'C3'] = count
        else:
               df.at[index, 'C3'] = count

    print(df)
         C1  C2  C3
    0    0   0   1
    1    0   0   1
    2    1   0   2
    3    1   1   2
    4    1   1   2
    5    0   1   2
    6    0   0   2
    7    0   0   2
    8    0   0   2
    9    1   0   3
    10   1   1   3
    11   1   1   3
    12   0   1   3
    13   0   0   3

对于具有300000行的数据帧,它有点慢,是否有简单的方法使其变得更快?

非常感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

您可以:

  • 创建一个系列counts,它是所需条件的布尔掩码(counts);
  • C3添加到值1 + counts.cumsum()的原始df中

注意:pandas根据索引值(<无>无顺序)将系列连接到数据框。进行一些破坏df或counts系列的中间操作会产生意外的结果。

代码:

counts = (df.C1 == 1) & (df.C2 == 0)
df["C3"] = 1 + counts.cumsum()

结果:

    C1  C2  C3
0    0   0   1
1    0   0   1
2    1   0   2
3    1   1   2
4    1   1   2
5    0   1   2
6    0   0   2
7    0   0   2
8    0   0   2
9    1   0   3
10   1   1   3
11   1   1   3
12   0   1   3
13   0   0   3

性能

让我们比较以下三个选项的性能:iterrowsdf.apply和上面的矢量化解决方案:

df = pd.DataFrame(dict(C1=np.random.choice(2,size=100000), C2=np.random.choice(2,size=100000)))

df1 = df.copy(deep=True)
df2 = df.copy(deep=True)
df3 = df.copy(deep=True)

def use_iterrows():
    count=1
    df1['C3'] = 0
    for index, row in df1.iterrows():
        if (row.C1 == 1) and (row.C2 == 0):
               count += 1 
               df1.at[index, 'C3'] = count
        else:
               df1.at[index, 'C3'] = count

def use_apply():
    df2['C3'] = df2.apply(lambda x: x['C1']==1 and x['C2']==0, axis=1).cumsum()+1

def use_vectorized():
    counts = (df3.C1 == 1) & (df3.C2 == 0)
    df3["C3"] = 1 + counts.cumsum()

%timeit use_iterrows()
# 8.23 s ± 159 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)    

%timeit use_apply()
# 1.54 s ± 27.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit use_vectorized()
# 1.28 ms ± 66.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

摘要:使用向量化函数是最快的(对于100k行的df,速度要快〜1000x(!))。我喜欢尽可能使用矢量化解决方案的习惯。 df.apply的优势在于它非常灵活,可以在矢量化操作难以实现的情况下使用。我认为我从来不需要过。

答案 1 :(得分:0)

简短答案:

df['C3'] = df.apply(lambda x: x['C1']==1 and x['C2']==0, axis=1).cumsum()+1

所需结果:

   C1   C2  C3
0   0   0   1
1   0   0   1
2   1   0   2
3   1   1   2
4   1   1   2
5   0   1   2
6   0   0   2
7   0   0   2
8   0   0   2
9   1   0   3
10  1   1   3
11  1   1   3
12  0   1   3
13  0   0   3

您需要记住的内容:

对于长数据,请勿使用迭代。它使速度大大降低。

应用-一种更好的替代方法,效率更高