我在熊猫中有以下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 |
+-------+--------+
答案 0 :(得分:5)
idxmax
和loc
进行分配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)
将eq
与cummax
一起使用
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行数据帧上执行,以测试可伸缩性。看来wen
和piRsquared
解决方案是最有效的。不要犹豫,赞成这些答案。
编辑:为透明起见,以下是用于执行测试的功能:
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
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