如何基于 pandas 中的 3 个不同条件以矢量化方式处理行组?
How to process groups of rows based on 3 different conditions in pandas hopefully in a vectorized way?
考虑一个包含两列的 Dataframe:timestamps
(已排序)和 temperature
(不一定已排序)以及定义 windows 的时间戳列表(开始和结束列表) ,
我想将这些 windows 中的每一个作为一个组来处理。
在每个组中,我想检索对应于等于或大于 temp_limit
的第一个 temp
值的时间戳。
当然,我想以最快的方式完成:)
一个例子可能会提供更好的解释,我已经使用 iterrows
实现了这个。拜托,有没有什么矢量化的方法来管理这个? (或者我认为 groupby()
,即使没有向量化,也会比 iterrows
快)
import numpy as np
import pandas as pd
# Define input data: Dataframe with 'ts' and 'temp' columns.
ts = pd.date_range(start='2020/01/01 08:00', end='2020/01/02 08:00', freq='2H')
temp = np.arange(len(ts)) + 10
df = pd.DataFrame({'ts': ts, 'temp':temp})
# 'windows' DataFrame gathers the list of timestamps in column 'ts',
# and list of temperature thresholds in 'temp_lim'.
ts_win = ts[::4]
temp_lim = temp[::4]+2
windows = pd.DataFrame({'ts_win': ts_win, 'temp_lim': temp_lim})[:-1]
# Doing now the processing in a non vectorized way
# Results are stored in column 'ts' of DataFrame 'res'
res = pd.DataFrame(columns=['ts'], index=range(len(windows)))
windows['later_ts_win'] = windows['ts_win'].shift(-1, fill_value=df['ts'].iloc[-1])
i=0
for row in windows.iterrows():
_, row = row
ts1, ts2 = row['ts_win'], row['later_ts_win']
m_df = (df['ts'] > ts1) & (df['ts'] <= ts2) & (df['temp'] >= row['temp_lim'])
res['ts'].iloc[i] = df.loc[m_df,'ts'].iloc[0]
i+=1
然后输入数据帧是:
df
ts temp
0 2020-01-01 08:00:00 10
1 2020-01-01 10:00:00 11
2 2020-01-01 12:00:00 12
3 2020-01-01 14:00:00 13
4 2020-01-01 16:00:00 14
5 2020-01-01 18:00:00 15
6 2020-01-01 20:00:00 16
7 2020-01-01 22:00:00 17
8 2020-01-02 00:00:00 18
9 2020-01-02 02:00:00 19
10 2020-01-02 04:00:00 20
11 2020-01-02 06:00:00 21
12 2020-01-02 08:00:00 22
windows
ts_win temp_lim
0 2020-01-01 08:00:00 12
1 2020-01-01 16:00:00 16
2 2020-01-02 00:00:00 20
结果是
res
ts
0 2020-01-01 12:00:00
1 2020-01-01 20:00:00
2 2020-01-02 04:00:00
因此,回顾循环的第一次迭代:
- 处理 ts > '2020-01-01 08:00:00' 且 <= '2020-01-01 16:00:00' 的行组
- 在该组中,检索到 temp 大于或等于“12”(
temp_lim
) 的第一个 ts
您可以在没有完全匹配的情况下使用 merge_asof。然后根据大于或等于限制的温度过滤数据集,在 ts_win
上聚合并获取第一行。然后您可以获取所需的列。
d = pd.merge_asof(df, windows, left_on='ts', right_on='ts_win', allow_exact_matches=False)
print(d.loc[d.temp >= d.temp_lim].groupby('ts_win').first())
ts temp temp_lim
ts_win
2020-01-01 08:00:00 2020-01-01 12:00:00 12 12.0
2020-01-01 16:00:00 2020-01-01 20:00:00 16 16.0
2020-01-02 00:00:00 2020-01-02 04:00:00 20 20.0
注意:merge_asof
期望两个数据集都按键排序。
考虑一个包含两列的 Dataframe:timestamps
(已排序)和 temperature
(不一定已排序)以及定义 windows 的时间戳列表(开始和结束列表) ,
我想将这些 windows 中的每一个作为一个组来处理。
在每个组中,我想检索对应于等于或大于 temp_limit
的第一个 temp
值的时间戳。
当然,我想以最快的方式完成:)
一个例子可能会提供更好的解释,我已经使用 iterrows
实现了这个。拜托,有没有什么矢量化的方法来管理这个? (或者我认为 groupby()
,即使没有向量化,也会比 iterrows
快)
import numpy as np
import pandas as pd
# Define input data: Dataframe with 'ts' and 'temp' columns.
ts = pd.date_range(start='2020/01/01 08:00', end='2020/01/02 08:00', freq='2H')
temp = np.arange(len(ts)) + 10
df = pd.DataFrame({'ts': ts, 'temp':temp})
# 'windows' DataFrame gathers the list of timestamps in column 'ts',
# and list of temperature thresholds in 'temp_lim'.
ts_win = ts[::4]
temp_lim = temp[::4]+2
windows = pd.DataFrame({'ts_win': ts_win, 'temp_lim': temp_lim})[:-1]
# Doing now the processing in a non vectorized way
# Results are stored in column 'ts' of DataFrame 'res'
res = pd.DataFrame(columns=['ts'], index=range(len(windows)))
windows['later_ts_win'] = windows['ts_win'].shift(-1, fill_value=df['ts'].iloc[-1])
i=0
for row in windows.iterrows():
_, row = row
ts1, ts2 = row['ts_win'], row['later_ts_win']
m_df = (df['ts'] > ts1) & (df['ts'] <= ts2) & (df['temp'] >= row['temp_lim'])
res['ts'].iloc[i] = df.loc[m_df,'ts'].iloc[0]
i+=1
然后输入数据帧是:
df
ts temp
0 2020-01-01 08:00:00 10
1 2020-01-01 10:00:00 11
2 2020-01-01 12:00:00 12
3 2020-01-01 14:00:00 13
4 2020-01-01 16:00:00 14
5 2020-01-01 18:00:00 15
6 2020-01-01 20:00:00 16
7 2020-01-01 22:00:00 17
8 2020-01-02 00:00:00 18
9 2020-01-02 02:00:00 19
10 2020-01-02 04:00:00 20
11 2020-01-02 06:00:00 21
12 2020-01-02 08:00:00 22
windows
ts_win temp_lim
0 2020-01-01 08:00:00 12
1 2020-01-01 16:00:00 16
2 2020-01-02 00:00:00 20
结果是
res
ts
0 2020-01-01 12:00:00
1 2020-01-01 20:00:00
2 2020-01-02 04:00:00
因此,回顾循环的第一次迭代:
- 处理 ts > '2020-01-01 08:00:00' 且 <= '2020-01-01 16:00:00' 的行组
- 在该组中,检索到 temp 大于或等于“12”(
temp_lim
) 的第一个 ts
您可以在没有完全匹配的情况下使用 merge_asof。然后根据大于或等于限制的温度过滤数据集,在 ts_win
上聚合并获取第一行。然后您可以获取所需的列。
d = pd.merge_asof(df, windows, left_on='ts', right_on='ts_win', allow_exact_matches=False)
print(d.loc[d.temp >= d.temp_lim].groupby('ts_win').first())
ts temp temp_lim
ts_win
2020-01-01 08:00:00 2020-01-01 12:00:00 12 12.0
2020-01-01 16:00:00 2020-01-01 20:00:00 16 16.0
2020-01-02 00:00:00 2020-01-02 04:00:00 20 20.0
注意:merge_asof
期望两个数据集都按键排序。