遍历大熊猫中的行以检查条件

时间:2018-08-27 15:09:46

标签: python pandas dataframe

我在熊猫中有以下DF。

+-------+-------+
| Col_A | Col_B |
+-------+-------+
|  1234 |       |
|  6267 |       |
|  6364 |       |
|   573 |       |
|     0 |       |
|   838 |       |
|    92 |       |
|  3221 |       |
+-------+-------+

Col_B应该用True或False值填充。默认情况下,它为False,但是当“看到”第一个0时,DF的其余部分应该为True。 DF有10万多行。

自从出现Col_A中的第一个“ 0”值以来,将col_B中的值设置为“ True”的最快方法是什么?

+-------+--------+
| Col_A | Col_B  |
+-------+--------+
|  1234 | False  |
|  6267 | False  |
|  6364 | False  |
|   573 | False  |
|     0 | True   |
|   838 | True   |
|    92 | True   |
|  3221 | True   |
+-------+--------+

6 个答案:

答案 0 :(得分:5)

使用idxmaxloc进行分配

idx = df.Col_A.eq(0).idxmax()
df['Col_B'] = False
df.loc[idx:, 'Col_B'] = True

   Col_A  Col_B
0   1234  False
1   6267  False
2   6364  False
3    573  False
4      0   True
5    838   True
6     92   True
7   3221   True

使用assign

这种方法避免了修改原始DataFrame。

df.assign(Col_B=(df.index >= idx))

答案 1 :(得分:5)

eqcummax一起使用

df.A.eq(0).cummax()
Out[5]: 
0    False
1    False
2    False
3    False
4     True
5     True
6     True
7     True
Name: A, dtype: bool

答案 2 :(得分:5)

您可以使用ufunc accumulate的Numpy的logical_or方法

df.assign(Col_B=np.logical_or.accumulate(df.Col_A.values == 0))

   Col_A  Col_B
0   1234  False
1   6267  False
2   6364  False
3    573  False
4      0   True
5    838   True
6     92   True
7   3221   True

答案 3 :(得分:4)

您可以将next与生成器表达式一起使用。如果在0出现在开头附近的大型系列中,这样做会更有效率。

@ user3483203的NumPy-based solution应该可以正常使用。

df = pd.DataFrame({'A': [1234, 6267, 6364, 573, 0, 838, 92, 3221]})

idx = next((i for i, j in enumerate(df['A']) if j == 0), len(df['A']))

df['B'] = ~(df.index < idx)

# more verbose alternative:
# df['B'] = np.where(df.index < idx, False, True)

print(df)

      A      B
0  1234  False
1  6267  False
2  6364  False
3   573  False
4     0   True
5   838   True
6    92   True
7  3221   True

答案 4 :(得分:3)

这里介绍了许多方法,我无法抗拒。我必须对两者进行一些性能比较:

%timeit vivek_kumar()
16.6 ms ± 495 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit numbered_user()
6.69 ms ± 116 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit warpri()
14 ms ± 216 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit jpp()
2.21 ms ± 96.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit wen()
991 µs ± 20.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit pirsquared()
938 µs ± 24.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

此比较已在80k行数据帧上执行,以测试可伸缩性。看来wenpiRsquared解决方案是最有效的。不要犹豫,赞成这些答案。

编辑:为透明起见,以下是用于执行测试的功能:

def vivek_kumar():
    data = df.copy()
    first_index = data.loc[data['Col_A'] == 0, 'Col_A'].index[0]
    data.loc[:first_index, 'Col_B'] = False
    data.loc[first_index:, 'Col_B'] = True

def numbered_user():
    data = df.copy()
    idx = data.Col_A.eq(0).idxmax()
    data['Col_B'] = False
    data.loc[idx:, 'Col_B'] = True

def warpri():
    data = df.copy()
    def update_col_b(col_a):
        return col_a == 0
    data['Col_B'] = data.Col_A.apply(update_col_b)

def jpp():
    data = df.copy()
    idx = next((i for i, j in enumerate(data['Col_A']) if j == 0), len(data['Col_A']))
    data['Col_B'] = ~(data.index < idx)

def wen():
    data = df.copy()
    data['Col_B'] = data.Col_A.eq(0).cummax()

def pirsquared():
    data = df.copy()
    # This would return a copy.  My preferred approach
    # return data.assign(Col_B=np.logical_or.accumulate(data.Col_A.values == 0))
    # This edits the dataframe in place but properly compares against the other proposals
    df['Col_B'] = np.logical_or.accumulate(data.Col_A.values == 0)

EDIT2:遵循piRSquared指示,这也是使用assign生成数据帧副本和使用=修改现有数据帧之间的比较:

def pirsquared1():
    data = df.copy()
    data = data.assign(Col_B=np.logical_or.accumulate(data.Col_A.values == 0))

%timeit pirsquared1()
923 µs ± 32.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

def pirsquared2():
    data = df.copy()
    df['Col_B'] = np.logical_or.accumulate(data.Col_A.values == 0)

%timeit pirsquared2()
598 µs ± 35.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

答案 5 :(得分:0)

ggplotfunction

中查找前0的索引
col_A

推荐方式(感谢@jpp):

first_index = df['col_A'][df['col_A'] == 0].index[0] - 1  #-1 to get index before 0

然后,用它来填充其他列:

first_index = df.loc[df['col_A'] == 0, 'col_A'].index[0] - 1