pandas 数据帧中前 N 行的条件均值和总和
Conditional mean and sum of previous N rows in pandas dataframe
关注的是这个示例性的 pandas 数据帧:
Measurement Trigger Valid
0 2.0 False True
1 4.0 False True
2 3.0 False True
3 0.0 True False
4 100.0 False True
5 3.0 False True
6 2.0 False True
7 1.0 True True
每当 Trigger
为 True
时,我希望计算最后 3 个(从当前开始)有效测量值的总和和平均值。如果列 Valid
为 True
,则测量值被视为有效。因此,让我们使用上述数据框中的两个示例进行说明:
Index 3
:应使用索引 2,1,0
。预计 Sum = 9.0, Mean = 3.0
Index 7
:应使用索引 7,6,5
。预计 Sum = 6.0, Mean = 2.0
我已经尝试 pandas.rolling
并创建新的、移位的列,但没有成功。请参阅以下我的测试摘录(应该直接 运行):
import unittest
import pandas as pd
import numpy as np
from pandas.util.testing import assert_series_equal
def create_sample_dataframe_2():
df = pd.DataFrame(
{"Measurement" : [2.0, 4.0, 3.0, 0.0, 100.0, 3.0, 2.0, 1.0 ],
"Valid" : [True, True, True, False, True, True, True, True],
"Trigger" : [False, False, False, True, False, False, False, True],
})
return df
def expected_result():
return pd.DataFrame({"Sum" : [np.nan, np.nan, np.nan, 9.0, np.nan, np.nan, np.nan, 6.0],
"Mean" :[np.nan, np.nan, np.nan, 3.0, np.nan, np.nan, np.nan, 2.0]})
class Data_Preparation_Functions(unittest.TestCase):
def test_backsummation(self):
N_SUMMANDS = 3
temp_vars = []
df = create_sample_dataframe_2()
for i in range(0,N_SUMMANDS):
temp_var = "M_{0}".format(i)
df[temp_var] = df["Measurement"].shift(i)
temp_vars.append(temp_var)
df["Sum"] = df[temp_vars].sum(axis=1)
df["Mean"] = df[temp_vars].mean(axis=1)
df.loc[(df["Trigger"]==False), "Sum"] = np.nan
df.loc[(df["Trigger"]==False), "Mean"] = np.nan
assert_series_equal(expected_result()["Sum"],df["Sum"])
assert_series_equal(expected_result()["Mean"],df["Mean"])
def test_rolling(self):
df = create_sample_dataframe_2()
df["Sum"] = df[(df["Valid"] == True)]["Measurement"].rolling(window=3).sum()
df["Mean"] = df[(df["Valid"] == True)]["Measurement"].rolling(window=3).mean()
df.loc[(df["Trigger"]==False), "Sum"] = np.nan
df.loc[(df["Trigger"]==False), "Mean"] = np.nan
assert_series_equal(expected_result()["Sum"],df["Sum"])
assert_series_equal(expected_result()["Mean"],df["Mean"])
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(Data_Preparation_Functions)
unittest.TextTestRunner(verbosity=2).run(suite)
非常感谢任何帮助或解决方案。谢谢和干杯!
编辑:澄清:这是我期望的结果数据框:
Measurement Trigger Valid Sum Mean
0 2.0 False True NaN NaN
1 4.0 False True NaN NaN
2 3.0 False True NaN NaN
3 0.0 True False 9.0 3.0
4 100.0 False True NaN NaN
5 3.0 False True NaN NaN
6 2.0 False True NaN NaN
7 1.0 True True 6.0 2.0
EDIT2:另一个说明:
我确实没有算错,但我没有把我的意图说清楚。这是使用相同数据框的另一个尝试:
让我们首先看一下 Trigger
列:我们在索引 3(绿色矩形)中找到第一个 True
。所以索引 3 是我们开始寻找的点。索引 3 处没有有效的测量值(第 Valid
列是 False
;红色矩形)。所以,我们开始往前追溯,直到我们累积了三行,其中 Valid
是 True
。这发生在索引 2,1 和 0 上。对于这三个索引,我们计算列 Measurement
(蓝色矩形)的总和和平均值:
- 总和:2.0 + 4.0 + 3.0 = 9.0
- 平均值:(2.0 + 4.0 + 3.0) / 3 = 3.0
现在我们开始这个小算法的下一次迭代:再次查找 Trigger
列中的下一个 True
。我们在索引 7(绿色矩形)处找到它。在索引 7 处也有一个有效的测量值,因此我们这次将其包括在内。对于我们的计算,我们使用索引 7,6 和 5(绿色矩形),因此得到:
- 总和:1.0 + 2.0 + 3.0 = 6.0
- 平均值:(1.0 + 2.0 + 3.0) / 3 = 2.0
我希望,这能更清楚地说明这个小问题。
这是一个选项,取 3 个周期的滚动平均值和总和
df['RollM'] = df.Measurement.rolling(window=3,min_periods=0).mean()
df['RollS'] = df.Measurement.rolling(window=3,min_periods=0).sum()
现在将 False Triggers 设置为 NaN
df.loc[df.Trigger == False,['RollS','RollM']] = np.nan
产量
Measurement Trigger Valid RollM RollS
0 2.0 False True NaN NaN
1 4.0 False True NaN NaN
2 3.0 False True NaN NaN
3 0.0 True False 2.333333 7.0
4 100.0 False True NaN NaN
5 3.0 False True NaN NaN
6 2.0 False True NaN NaN
7 1.0 True True 2.000000 6.0
编辑,更新以反映有效参数
df['mean'],df['sum'] = np.nan,np.nan
roller = df.Measurement.rolling(window=3,min_periods=0).agg(['mean','sum'])
df.loc[(df.Trigger == True) & (df.Valid == True),['mean','sum']] = roller
df.loc[(df.Trigger == True) & (df.Valid == False),['mean','sum']] = roller.shift(1)
产量
Measurement Trigger Valid mean sum
0 2.0 False True NaN NaN
1 4.0 False True NaN NaN
2 3.0 False True NaN NaN
3 0.0 True False 3.0 9.0
4 100.0 False True NaN NaN
5 3.0 False True NaN NaN
6 2.0 False True NaN NaN
7 1.0 True True 2.0 6.0
关注的是这个示例性的 pandas 数据帧:
Measurement Trigger Valid
0 2.0 False True
1 4.0 False True
2 3.0 False True
3 0.0 True False
4 100.0 False True
5 3.0 False True
6 2.0 False True
7 1.0 True True
每当 Trigger
为 True
时,我希望计算最后 3 个(从当前开始)有效测量值的总和和平均值。如果列 Valid
为 True
,则测量值被视为有效。因此,让我们使用上述数据框中的两个示例进行说明:
Index 3
:应使用索引2,1,0
。预计Sum = 9.0, Mean = 3.0
Index 7
:应使用索引7,6,5
。预计Sum = 6.0, Mean = 2.0
我已经尝试 pandas.rolling
并创建新的、移位的列,但没有成功。请参阅以下我的测试摘录(应该直接 运行):
import unittest
import pandas as pd
import numpy as np
from pandas.util.testing import assert_series_equal
def create_sample_dataframe_2():
df = pd.DataFrame(
{"Measurement" : [2.0, 4.0, 3.0, 0.0, 100.0, 3.0, 2.0, 1.0 ],
"Valid" : [True, True, True, False, True, True, True, True],
"Trigger" : [False, False, False, True, False, False, False, True],
})
return df
def expected_result():
return pd.DataFrame({"Sum" : [np.nan, np.nan, np.nan, 9.0, np.nan, np.nan, np.nan, 6.0],
"Mean" :[np.nan, np.nan, np.nan, 3.0, np.nan, np.nan, np.nan, 2.0]})
class Data_Preparation_Functions(unittest.TestCase):
def test_backsummation(self):
N_SUMMANDS = 3
temp_vars = []
df = create_sample_dataframe_2()
for i in range(0,N_SUMMANDS):
temp_var = "M_{0}".format(i)
df[temp_var] = df["Measurement"].shift(i)
temp_vars.append(temp_var)
df["Sum"] = df[temp_vars].sum(axis=1)
df["Mean"] = df[temp_vars].mean(axis=1)
df.loc[(df["Trigger"]==False), "Sum"] = np.nan
df.loc[(df["Trigger"]==False), "Mean"] = np.nan
assert_series_equal(expected_result()["Sum"],df["Sum"])
assert_series_equal(expected_result()["Mean"],df["Mean"])
def test_rolling(self):
df = create_sample_dataframe_2()
df["Sum"] = df[(df["Valid"] == True)]["Measurement"].rolling(window=3).sum()
df["Mean"] = df[(df["Valid"] == True)]["Measurement"].rolling(window=3).mean()
df.loc[(df["Trigger"]==False), "Sum"] = np.nan
df.loc[(df["Trigger"]==False), "Mean"] = np.nan
assert_series_equal(expected_result()["Sum"],df["Sum"])
assert_series_equal(expected_result()["Mean"],df["Mean"])
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(Data_Preparation_Functions)
unittest.TextTestRunner(verbosity=2).run(suite)
非常感谢任何帮助或解决方案。谢谢和干杯!
编辑:澄清:这是我期望的结果数据框:
Measurement Trigger Valid Sum Mean
0 2.0 False True NaN NaN
1 4.0 False True NaN NaN
2 3.0 False True NaN NaN
3 0.0 True False 9.0 3.0
4 100.0 False True NaN NaN
5 3.0 False True NaN NaN
6 2.0 False True NaN NaN
7 1.0 True True 6.0 2.0
EDIT2:另一个说明:
我确实没有算错,但我没有把我的意图说清楚。这是使用相同数据框的另一个尝试:
让我们首先看一下 Trigger
列:我们在索引 3(绿色矩形)中找到第一个 True
。所以索引 3 是我们开始寻找的点。索引 3 处没有有效的测量值(第 Valid
列是 False
;红色矩形)。所以,我们开始往前追溯,直到我们累积了三行,其中 Valid
是 True
。这发生在索引 2,1 和 0 上。对于这三个索引,我们计算列 Measurement
(蓝色矩形)的总和和平均值:
- 总和:2.0 + 4.0 + 3.0 = 9.0
- 平均值:(2.0 + 4.0 + 3.0) / 3 = 3.0
现在我们开始这个小算法的下一次迭代:再次查找 Trigger
列中的下一个 True
。我们在索引 7(绿色矩形)处找到它。在索引 7 处也有一个有效的测量值,因此我们这次将其包括在内。对于我们的计算,我们使用索引 7,6 和 5(绿色矩形),因此得到:
- 总和:1.0 + 2.0 + 3.0 = 6.0
- 平均值:(1.0 + 2.0 + 3.0) / 3 = 2.0
我希望,这能更清楚地说明这个小问题。
这是一个选项,取 3 个周期的滚动平均值和总和
df['RollM'] = df.Measurement.rolling(window=3,min_periods=0).mean()
df['RollS'] = df.Measurement.rolling(window=3,min_periods=0).sum()
现在将 False Triggers 设置为 NaN
df.loc[df.Trigger == False,['RollS','RollM']] = np.nan
产量
Measurement Trigger Valid RollM RollS
0 2.0 False True NaN NaN
1 4.0 False True NaN NaN
2 3.0 False True NaN NaN
3 0.0 True False 2.333333 7.0
4 100.0 False True NaN NaN
5 3.0 False True NaN NaN
6 2.0 False True NaN NaN
7 1.0 True True 2.000000 6.0
编辑,更新以反映有效参数
df['mean'],df['sum'] = np.nan,np.nan
roller = df.Measurement.rolling(window=3,min_periods=0).agg(['mean','sum'])
df.loc[(df.Trigger == True) & (df.Valid == True),['mean','sum']] = roller
df.loc[(df.Trigger == True) & (df.Valid == False),['mean','sum']] = roller.shift(1)
产量
Measurement Trigger Valid mean sum
0 2.0 False True NaN NaN
1 4.0 False True NaN NaN
2 3.0 False True NaN NaN
3 0.0 True False 3.0 9.0
4 100.0 False True NaN NaN
5 3.0 False True NaN NaN
6 2.0 False True NaN NaN
7 1.0 True True 2.0 6.0