根据条件更新 groupby 对象上的 df 列值

Update df column values on groupby object based on condition

我无法找到一种有效的方法来更新大型 pandas DataFrame 中的某些列值。

下面的代码创建了一个与我正在使用的格式类似的 DataFrame。数据摘要:DataFrame 包含三天的消耗数据,每天分为 10 个测量周期。每个测量周期也记录在四个独立的过程中,即初步读数、日终读数和两个后来的修订,所有更新都记录在 Last_Update 列和日期。

dates = ['2022-01-01']*40 + ['2022-01-02']*40 + ['2022-01-03']*40
periods = list(range(1,11))*12
versions = (['PRELIM'] * 10 + ['DAILY'] * 10 + ['REVISE'] * 20) * 3


data = {'Date': dates,
 'Period' : periods,
 'Version': versions,
 'Consumption': np.random.randint(1, 30, 120)}
 
df = pd.DataFrame(data)
df.Date = pd.to_datetime(df.Date)

## Add random times to the REVISE Last_Update values
df['Last_Update'] = df['Date'].apply(lambda x: x + pd.Timedelta(hours=np.random.randint(1,23), minutes=np.random.randint(1,59)))
df['Last_Update'] = df['Last_Update'].where(df.Version == 'REVISE', df['Date'])

问题是两个修订类别都由相同的值指定:“REVISE”。其中一个“REVISE”值必须更改为类似“REVISE_2”的值。如果您按以下方式对数据进行分组 df.groupby(['Date', 'Period', 'Version', 'Last_Update'])['Consumption'].sum(),您可以看到每天的每个期间有两个 Last_Update 日期用于 REVISE。所以我们需要将日期最大的REVISE设置为REVISE_2.

我设法找到解决方案的唯一方法是使用一个非常复杂的函数和 apply 方法来测试哪个日期更大并存储其索引,然后使用 loc 更改值。这最终导致小部分数据花费了大量时间(完整的数据集有数百万行)。

我觉得有一个使用 groupby 函数的简单解决方案,因为我在导航多索引输出时遇到困难。

如有任何帮助,我们将不胜感激。

我们在一些分组后使用 idxmax 计算最大修订日期的索引,然后更改标签:

last_revised_date_idx = df[df['Version'] == 'REVISE'].groupby(['Date', 'Period'], group_keys = False)['Last_Update'].idxmax()
df.loc[last_revised_date_idx, 'Version'] = 'REVISE_2'

检查输出:

df.groupby(['Date', 'Period', 'Version', 'Last_Update'])['Consumption'].count().head(20)

产生

Date        Period  Version   Last_Update        
2022-01-01  1       DAILY     2022-01-01 00:00:00    1
                    PRELIM    2022-01-01 00:00:00    1
                    REVISE    2022-01-01 03:50:00    1
                    REVISE_2  2022-01-01 12:10:00    1
            2       DAILY     2022-01-01 00:00:00    1
                    PRELIM    2022-01-01 00:00:00    1
                    REVISE    2022-01-01 10:45:00    1
                    REVISE_2  2022-01-01 22:05:00    1
            3       DAILY     2022-01-01 00:00:00    1
                    PRELIM    2022-01-01 00:00:00    1
                    REVISE    2022-01-01 17:03:00    1
                    REVISE_2  2022-01-01 19:10:00    1
            4       DAILY     2022-01-01 00:00:00    1
                    PRELIM    2022-01-01 00:00:00    1
                    REVISE    2022-01-01 15:23:00    1
                    REVISE_2  2022-01-01 18:08:00    1
            5       DAILY     2022-01-01 00:00:00    1
                    PRELIM    2022-01-01 00:00:00    1
                    REVISE    2022-01-01 12:19:00    1
                    REVISE_2  2022-01-01 18:04:00    1