Python pandas: 将函数应用到 dataframe.rolling()
Python pandas: apply a function to dataframe.rolling()
我有这个数据框:
In[1]df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
In[2]df
Out[2]:
0 1 2 3 4
0 1 2 3 4 5
1 6 7 8 9 10
2 11 12 13 14 15
3 16 17 18 19 20
4 21 22 23 24 25
我需要实现这个:
- 对于我的数据框中的每一行,
- 如果任意 3 个连续单元格中有 2 个或更多值大于 10,
- 那么这 3 个单元格中的最后一个应该标记为 True。
根据上述标准,生成的数据帧 df1 应与其中的 True 或 False 大小相同:
In[3]df1
Out[3]:
0 1 2 3 4
0 NaN NaN False False False
1 NaN NaN False False False
2 NaN NaN True True True
3 NaN NaN True True True
4 NaN NaN True True True
- df1.iloc[0,1] 是 NaN 因为在该单元格中,只给出了两个数字,但至少需要 3 个数字才能进行测试。
- df1.iloc[1,3] 为假,因为 [7,8,9] 中的 none 大于 10
- df1.iloc[3,4] 为真,因为 [18,19,20] 中的 2 或更多大于 10
我认为带有函数的 dataframe.rolling.apply() 可能是解决方案,但究竟如何呢?
你说得对,使用 rolling()
是正确的方法。但是,您必须记住,因为 rolling()
将 window 末尾的值替换为新值,所以您不能只将 window 标记为 True
当条件不适用时也会得到 False
下面是使用示例数据框并执行所需转换的代码:
df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
现在,定义一个以window为参数的函数,returns是否满足条件
def fun(x):
num = 0
for i in x:
num += 1 if i > 10 else 0
return 1 if num >= 2 else -1
我已将阈值硬编码为 10。因此,如果在任何 window 中,大于 10 的值的数量大于或等于 2,那么最后一个值将替换为 1(表示 True),否则它被替换为 -1(表示 False)。
如果您想将阈值参数保留为变量,请查看 this 答案以将它们作为参数传递。
现在在滚动 window 上应用函数,使用 window 大小作为 3,轴 1 另外如果你不想要 NaN 那么你也可以将 min_periods 设置为 1在参数中。
df.rolling(3, axis=1).apply(fun)
产生的输出为
0 1 2 3 4
0 NaN NaN -1.0 -1.0 -1.0
1 NaN NaN -1.0 -1.0 -1.0
2 NaN NaN 1.0 1.0 1.0
3 NaN NaN 1.0 1.0 1.0
4 NaN NaN 1.0 1.0 1.0
你需要 -
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
df1 = df.apply(lambda x: pd.Series([np.nan, np.nan]+[all(j>10 for j in i) for i in zip(x[0::1], x[1::1], x[2::1])]), axis=1)
print(df1)
输出
0 1 2 3 4
0 NaN NaN False False False
1 NaN NaN False False False
2 NaN NaN True True True
3 NaN NaN True True True
4 NaN NaN True True True
说明
list(zip(x[0::1], x[1::1], x[2::1])
将其分解为每行一次取 3 列 -
0 [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
1 [(6, 7, 8), (7, 8, 9), (8, 9, 10)]
2 [(11, 12, 13), (12, 13, 14), (13, 14, 15)]
3 [(16, 17, 18), (17, 18, 19), (18, 19, 20)]
4 [(21, 22, 23), (22, 23, 24), (23, 24, 25)]
all(j>10 for j in i)
检查元组列表中的每个元素,如果元组中的所有元素都大于 10
,则输出 True
连接 [np.nan, np.nan]
以匹配您的输出。希望对您有所帮助。
在布尔数据框上使用 sum
。
df.gt(10).rolling(3, axis=1).sum().ge(2)
0 1 2 3 4
0 False False False False False
1 False False False False False
2 False False True True True
3 False False True True True
4 False False True True True
您可以通过屏蔽 where na 来确定请求的确切输出。
df.gt(10).rolling(3, axis=1).sum().pipe(lambda d: d.ge(2).mask(d.isna()))
0 1 2 3 4
0 NaN NaN False False False
1 NaN NaN False False False
2 NaN NaN True True True
3 NaN NaN True True True
4 NaN NaN True True True
我有这个数据框:
In[1]df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
In[2]df
Out[2]:
0 1 2 3 4
0 1 2 3 4 5
1 6 7 8 9 10
2 11 12 13 14 15
3 16 17 18 19 20
4 21 22 23 24 25
我需要实现这个:
- 对于我的数据框中的每一行,
- 如果任意 3 个连续单元格中有 2 个或更多值大于 10,
- 那么这 3 个单元格中的最后一个应该标记为 True。
根据上述标准,生成的数据帧 df1 应与其中的 True 或 False 大小相同:
In[3]df1
Out[3]:
0 1 2 3 4
0 NaN NaN False False False
1 NaN NaN False False False
2 NaN NaN True True True
3 NaN NaN True True True
4 NaN NaN True True True
- df1.iloc[0,1] 是 NaN 因为在该单元格中,只给出了两个数字,但至少需要 3 个数字才能进行测试。
- df1.iloc[1,3] 为假,因为 [7,8,9] 中的 none 大于 10
- df1.iloc[3,4] 为真,因为 [18,19,20] 中的 2 或更多大于 10
我认为带有函数的 dataframe.rolling.apply() 可能是解决方案,但究竟如何呢?
你说得对,使用 rolling()
是正确的方法。但是,您必须记住,因为 rolling()
将 window 末尾的值替换为新值,所以您不能只将 window 标记为 True
当条件不适用时也会得到 False
下面是使用示例数据框并执行所需转换的代码:
df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
现在,定义一个以window为参数的函数,returns是否满足条件
def fun(x):
num = 0
for i in x:
num += 1 if i > 10 else 0
return 1 if num >= 2 else -1
我已将阈值硬编码为 10。因此,如果在任何 window 中,大于 10 的值的数量大于或等于 2,那么最后一个值将替换为 1(表示 True),否则它被替换为 -1(表示 False)。
如果您想将阈值参数保留为变量,请查看 this 答案以将它们作为参数传递。
现在在滚动 window 上应用函数,使用 window 大小作为 3,轴 1 另外如果你不想要 NaN 那么你也可以将 min_periods 设置为 1在参数中。
df.rolling(3, axis=1).apply(fun)
产生的输出为
0 1 2 3 4
0 NaN NaN -1.0 -1.0 -1.0
1 NaN NaN -1.0 -1.0 -1.0
2 NaN NaN 1.0 1.0 1.0
3 NaN NaN 1.0 1.0 1.0
4 NaN NaN 1.0 1.0 1.0
你需要 -
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
df1 = df.apply(lambda x: pd.Series([np.nan, np.nan]+[all(j>10 for j in i) for i in zip(x[0::1], x[1::1], x[2::1])]), axis=1)
print(df1)
输出
0 1 2 3 4
0 NaN NaN False False False
1 NaN NaN False False False
2 NaN NaN True True True
3 NaN NaN True True True
4 NaN NaN True True True
说明
list(zip(x[0::1], x[1::1], x[2::1])
将其分解为每行一次取 3 列 -
0 [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
1 [(6, 7, 8), (7, 8, 9), (8, 9, 10)]
2 [(11, 12, 13), (12, 13, 14), (13, 14, 15)]
3 [(16, 17, 18), (17, 18, 19), (18, 19, 20)]
4 [(21, 22, 23), (22, 23, 24), (23, 24, 25)]
all(j>10 for j in i)
检查元组列表中的每个元素,如果元组中的所有元素都大于 10
,则输出True
连接 [np.nan, np.nan]
以匹配您的输出。希望对您有所帮助。
在布尔数据框上使用 sum
。
df.gt(10).rolling(3, axis=1).sum().ge(2)
0 1 2 3 4
0 False False False False False
1 False False False False False
2 False False True True True
3 False False True True True
4 False False True True True
您可以通过屏蔽 where na 来确定请求的确切输出。
df.gt(10).rolling(3, axis=1).sum().pipe(lambda d: d.ge(2).mask(d.isna()))
0 1 2 3 4
0 NaN NaN False False False
1 NaN NaN False False False
2 NaN NaN True True True
3 NaN NaN True True True
4 NaN NaN True True True