繁体   English   中英

如何使用 pandas 根据条件将列值替换为另一行列值?

[英]How to replace column value with another rows column value based on condition using pandas?

有没有更好的方法来进行以下操作?

df = pd.DataFrame(data={
    "id": ['a', 'a', 'a', 'b', 'b', 'b', 'b'],
    "date": ["2020-01-01", "2020-01-11", "2020-01-10", "2020-01-06", "2020-02-01", "2020-02-22", "2020-02-20"],
    "type": ["start", "start", "closing", "start", "start", "closing", "closing"],
})

for id in df['id'].unique():
    closing_date = df.loc[(df['id'] == id) & (df['type'] == 'closing'), 'date'].min()
    df.loc[(df['id'] == id) & (df['date'] > closing_date), 'date'] = closing_date

我认为您可以在您开始使用的完全程序化(但相当可读)方法和其他答案中更完整的 pandas (但可读性较差,恕我直言)方法之间找到一个很好的中间立场,方法是将您的逻辑弹出为一个 function 在一个只有“id”的子数据帧上运行,然后简单地应用:

def make_start_precede_close(subdf):
    closing_date = subdf.loc[subdf['type'] == 'closing', 'date'].min()
    subdf.loc[subdf['date'] > closing_date, 'date'] = closing_date
    return subdf

df.groupby("id").apply(make_start_precede_close)

最终,您必须在可测试性、可重用性、可读性和性能之间做出权衡。 Pure-pandas 可能会在性能上获胜(尽管不一定),但根据我的经验,在其他类别中弹出明确的 function 会获胜。

避免逐行(或逐个标识)做事。 首先,我对变量id进行分组并找到最小日期。 然后我将这些数据与原始 dataframe 合并以创建一个closing_date列,该列对每一行都有一个值。 现在我们只需要从原始列dateclosing_date中取最小值。 最后,我们删除了closing_date列。

closing_date = df[df['type'] == 'closing'].groupby('id').date.min()
df['closing_date'] = df.merge(closing_date, on='id').date_y

df['date'] = df[['date', 'closing_date']].min(axis=1)
df = df.drop(columns='closing_date')

Output:

  id        date     type
0  a  2020-01-01    start
1  a  2020-01-10    start
2  a  2020-01-10  closing
3  b  2020-01-06    start
4  b  2020-02-01    start
5  b  2020-02-20    start
6  b  2020-02-20  closing

您可以使用groupby.transform获取每个组的结束日期,然后用 boolean 索引替换较大的值:

closing = (df['date'].where(df['type'].eq('closing'))
           .groupby(df['id']).transform('last')
          )

df.loc[df['date'].gt(closing), 'date'] = closing

output:

  id        date     type
0  a  2020-01-01    start
1  a  2020-01-10    start
2  a  2020-01-10  closing
3  b  2020-01-06    start
4  b  2020-02-01    start
5  b  2020-02-20    start
6  b  2020-02-20  closing

如果您每个 id 有多个“关闭”并希望确保获得最新的:

closing = (df['date'].sort_values()
           .where(df['type'].eq('closing'))
           .groupby(df['id']).transform('last')
          )

df.loc[df['date'].gt(closing), 'date'] = closing

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM