python - 被 pandas 条件 and/or 布尔索引难住了
python - stumped by pandas conditionals and/or boolean indexing
我在使用条件/布尔索引时遇到问题。我正在尝试使用逻辑填充数据帧(dfp),该逻辑以来自类似形状的数据帧(dfs)的数据加上自身的前一行(dfp)为条件。
这是我最近的失败...
import pandas as pd
dfs = pd.DataFrame({'a':[1,0,-1,0,1,0,0,-1,0,0],'b':[0,1,0,0,-1,0,1,0,-1,0]})
In [171]: dfs
Out[171]:
a b
0 1 0
1 0 1
2 -1 0
3 0 0
4 1 -1
5 0 0
6 0 1
7 -1 0
8 0 -1
9 0 0
dfp = pd.DataFrame(index=dfs.index,columns=dfs.columns)
dfp[(dfs==1)|((dfp.shift(1)==1)&(dfs!=-1))] = 1
In [166]: dfp.fillna(0)
Out[166]:
a b
0 1.0 0.0
1 0.0 1.0
2 0.0 0.0
3 0.0 0.0
4 1.0 0.0
5 0.0 0.0
6 0.0 1.0
7 0.0 0.0
8 0.0 0.0
9 0.0 0.0
因此,如果满足两个条件之一,我希望 dfp 在第 n 行中有一个 1:
1) dfs same row = 1 or 2) both dfp previous row = 1 and dfs same row <> -1
我希望我的最终输出看起来像这样:
a b
0 1 0
1 1 1
2 0 1
3 0 1
4 1 0
5 1 0
6 1 1
7 0 1
8 0 0
9 0 0
更新/编辑:
有时视觉效果更有帮助 - 下面是它在 Excel 中的映射方式。
提前致谢,非常感谢您的宝贵时间。
让我们总结一下不变量:
- 如果
dfs
值为 1
,则 dfp
值为 1
。
- 如果
dfs
值为 -1
,则 dfp
值为 0
。
- 如果
dfs
值为 0
则 dfp
值为 1
如果前一个 dfp
值为 1
否则为0
.
或者用另一种方式表述:
- 如果第一个值为
1
,则dfp
以1
开头,否则0
dfp
值是 0
,直到 dfs
中有一个 1
。
dfp
值是 1
,直到 dfs
中有一个 -1
。
这在python中很容易表述:
def create_new_column(dfs_col):
newcol = np.zeros_like(dfs_col)
if dfs_col[0] == 1:
last = 1
else:
last = 0
for idx, val in enumerate(dfs_col):
if last == 1 and val == -1:
last = 0
if last == 0 and val == 1:
last = 1
newcol[idx] = last
return newcol
测试:
>>> create_new_column(dfs.a)
array([1, 1, 0, 0, 1, 1, 1, 0, 0, 0], dtype=int64)
>>> create_new_column(dfs.b)
array([0, 1, 1, 1, 0, 0, 1, 1, 0, 0], dtype=int64)
然而,这在 Python 中非常低效,因为遍历 numpy 数组(和 pandas Series/DataFrames)很慢,而且 [=79=41=] 中的循环=] 也很低效。
但是,如果你有 numba
或 Cython
,你可以编译它,它(可能)比任何 NumPy 解决方案都快,因为 NumPy 需要多次滚动 and/or累积运算。
例如 numba:
>>> import numba
>>> numba_version = numba.njit(create_new_column) # compilation step
>>> numba_version(np.asarray(dfs.a)) # need cast to np.array
array([1, 1, 0, 0, 1, 1, 1, 0, 0, 0], dtype=int64)
>>> numba_version(np.asarray(dfs.b)) # need cast to np.array
array([0, 1, 1, 1, 0, 0, 1, 1, 0, 0], dtype=int64)
即使 dfs
有数百万行,numba 解决方案也只需要几毫秒:
>>> dfs = pd.DataFrame({'a':np.random.randint(-1, 2, 1000000),'b':np.random.randint(-1, 2, 1000000)})
>>> %timeit numba_version(np.asarray(dfs.b))
100 loops, best of 3: 9.37 ms per loop
这不是最好的方法,但确实有效。
dfs = pd.DataFrame({'a':[1,0,-1,0,1,0,0,-1,0,0],'b':[0,1,0,0,-1,0,1,0,-1,0]})
dfp = dfs.copy()
定义函数如下。 'last' 这里的用法有点老套。
last = [0]
def f( x ):
if x == 1:
x = 1
elif x != -1 and last[0] == 1:
x = 1
else:
x = 0
last[0] = x
return x
只需在每一列上应用 func f。
dfp.a = dfp.a.apply( f )
dfp
a b
0 1 0
1 1 1
2 0 0
3 0 0
4 1 -1
5 1 0
6 1 1
7 0 0
8 0 -1
9 0 0
col b 同样如此。不要忘记重新初始化 'last'.
last[0] = 0
dfp.b = dfp.b.apply( f )
dfp
a b
0 1 0
1 1 1
2 0 1
3 0 1
4 1 0
5 1 0
6 1 1
7 0 1
8 0 0
9 0 0
我在使用条件/布尔索引时遇到问题。我正在尝试使用逻辑填充数据帧(dfp),该逻辑以来自类似形状的数据帧(dfs)的数据加上自身的前一行(dfp)为条件。 这是我最近的失败...
import pandas as pd
dfs = pd.DataFrame({'a':[1,0,-1,0,1,0,0,-1,0,0],'b':[0,1,0,0,-1,0,1,0,-1,0]})
In [171]: dfs
Out[171]:
a b
0 1 0
1 0 1
2 -1 0
3 0 0
4 1 -1
5 0 0
6 0 1
7 -1 0
8 0 -1
9 0 0
dfp = pd.DataFrame(index=dfs.index,columns=dfs.columns)
dfp[(dfs==1)|((dfp.shift(1)==1)&(dfs!=-1))] = 1
In [166]: dfp.fillna(0)
Out[166]:
a b
0 1.0 0.0
1 0.0 1.0
2 0.0 0.0
3 0.0 0.0
4 1.0 0.0
5 0.0 0.0
6 0.0 1.0
7 0.0 0.0
8 0.0 0.0
9 0.0 0.0
因此,如果满足两个条件之一,我希望 dfp 在第 n 行中有一个 1:
1) dfs same row = 1 or 2) both dfp previous row = 1 and dfs same row <> -1
我希望我的最终输出看起来像这样:
a b
0 1 0
1 1 1
2 0 1
3 0 1
4 1 0
5 1 0
6 1 1
7 0 1
8 0 0
9 0 0
更新/编辑: 有时视觉效果更有帮助 - 下面是它在 Excel 中的映射方式。
提前致谢,非常感谢您的宝贵时间。
让我们总结一下不变量:
- 如果
dfs
值为1
,则dfp
值为1
。 - 如果
dfs
值为-1
,则dfp
值为0
。 - 如果
dfs
值为0
则dfp
值为1
如果前一个dfp
值为1
否则为0
.
或者用另一种方式表述:
- 如果第一个值为
1
,则dfp
以1
开头,否则0
dfp
值是0
,直到dfs
中有一个1
。dfp
值是1
,直到dfs
中有一个-1
。
这在python中很容易表述:
def create_new_column(dfs_col):
newcol = np.zeros_like(dfs_col)
if dfs_col[0] == 1:
last = 1
else:
last = 0
for idx, val in enumerate(dfs_col):
if last == 1 and val == -1:
last = 0
if last == 0 and val == 1:
last = 1
newcol[idx] = last
return newcol
测试:
>>> create_new_column(dfs.a)
array([1, 1, 0, 0, 1, 1, 1, 0, 0, 0], dtype=int64)
>>> create_new_column(dfs.b)
array([0, 1, 1, 1, 0, 0, 1, 1, 0, 0], dtype=int64)
然而,这在 Python 中非常低效,因为遍历 numpy 数组(和 pandas Series/DataFrames)很慢,而且 [=79=41=] 中的循环=] 也很低效。
但是,如果你有 numba
或 Cython
,你可以编译它,它(可能)比任何 NumPy 解决方案都快,因为 NumPy 需要多次滚动 and/or累积运算。
例如 numba:
>>> import numba
>>> numba_version = numba.njit(create_new_column) # compilation step
>>> numba_version(np.asarray(dfs.a)) # need cast to np.array
array([1, 1, 0, 0, 1, 1, 1, 0, 0, 0], dtype=int64)
>>> numba_version(np.asarray(dfs.b)) # need cast to np.array
array([0, 1, 1, 1, 0, 0, 1, 1, 0, 0], dtype=int64)
即使 dfs
有数百万行,numba 解决方案也只需要几毫秒:
>>> dfs = pd.DataFrame({'a':np.random.randint(-1, 2, 1000000),'b':np.random.randint(-1, 2, 1000000)})
>>> %timeit numba_version(np.asarray(dfs.b))
100 loops, best of 3: 9.37 ms per loop
这不是最好的方法,但确实有效。
dfs = pd.DataFrame({'a':[1,0,-1,0,1,0,0,-1,0,0],'b':[0,1,0,0,-1,0,1,0,-1,0]})
dfp = dfs.copy()
定义函数如下。 'last' 这里的用法有点老套。
last = [0]
def f( x ):
if x == 1:
x = 1
elif x != -1 and last[0] == 1:
x = 1
else:
x = 0
last[0] = x
return x
只需在每一列上应用 func f。
dfp.a = dfp.a.apply( f )
dfp
a b
0 1 0
1 1 1
2 0 0
3 0 0
4 1 -1
5 1 0
6 1 1
7 0 0
8 0 -1
9 0 0
col b 同样如此。不要忘记重新初始化 'last'.
last[0] = 0
dfp.b = dfp.b.apply( f )
dfp
a b
0 1 0
1 1 1
2 0 1
3 0 1
4 1 0
5 1 0
6 1 1
7 0 1
8 0 0
9 0 0