如何基于 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

因此,回顾循环的第一次迭代:

您可以在没有完全匹配的情况下使用 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 期望两个数据集都按键排序。