【问题标题】:Pandas - Replace Duplicates with Nan and Keep RowPandas - 用 Nan 替换重复项并保持行
【发布时间】:2020-10-09 04:09:53
【问题描述】:

如何在保留行的同时用 NaN 替换每个组的重复项?

我需要保留行而不删除并且可能保留它首先出现的第一个原始值。

import pandas as pd
from datetime import timedelta

df = pd.DataFrame({
    'date': ['2019-01-01 00:00:00','2019-01-01 01:00:00','2019-01-01 02:00:00', '2019-01-01 03:00:00',
             '2019-09-01 02:00:00','2019-09-01 03:00:00','2019-09-01 04:00:00', '2019-09-01 05:00:00'],
    'value': [10,10,10,10,12,12,12,12],
    'ID': ['Jackie','Jackie','Jackie','Jackie','Zoop','Zoop','Zoop','Zoop',]
})

df['date'] = pd.to_datetime(df['date'], infer_datetime_format=True)


date    value   ID
0   2019-01-01 00:00:00 10  Jackie
1   2019-01-01 01:00:00 10  Jackie
2   2019-01-01 02:00:00 10  Jackie
3   2019-01-01 03:00:00 10  Jackie
4   2019-09-01 02:00:00 12  Zoop
5   2019-09-01 03:00:00 12  Zoop
6   2019-09-01 04:00:00 12  Zoop
7   2019-09-01 05:00:00 12  Zoop

所需的数据框:

date    value   ID
0   2019-01-01 00:00:00 10  Jackie
1   2019-01-01 01:00:00 NaN Jackie
2   2019-01-01 02:00:00 NaN Jackie
3   2019-01-01 03:00:00 NaN Jackie
4   2019-09-01 02:00:00 12  Zoop
5   2019-09-01 03:00:00 NaN Zoop
6   2019-09-01 04:00:00 NaN Zoop
7   2019-09-01 05:00:00 NaN Zoop

编辑:

重复值只能在同一日期删除,与频率无关。因此,如果值 10 在 1 月 1 日出现两次,在 1 月 2 日出现 3 次,则值 10 应该只在 1 月 1 日和 1 月 2 日出现一次。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    我假设您检查列 valueID 的重复项,并进一步检查列 datedate

    df.loc[df.assign(d=df.date.dt.date).duplicated(['value','ID', 'd']), 'value'] = np.nan
    
    Out[269]:
                     date  value      ID
    0 2019-01-01 00:00:00   10.0  Jackie
    1 2019-01-01 01:00:00    NaN  Jackie
    2 2019-01-01 02:00:00    NaN  Jackie
    3 2019-01-01 03:00:00    NaN  Jackie
    4 2019-09-01 02:00:00   12.0    Zoop
    5 2019-09-01 03:00:00    NaN    Zoop
    6 2019-09-01 04:00:00    NaN    Zoop
    7 2019-09-01 05:00:00    NaN    Zoop
    

    正如@Trenton 建议的那样,您可以使用pd.NA 来避免导入numpy

    注意:@rafaelc 建议:这里是解释pd.NAnp.nan https://pandas.pydata.org/pandas-docs/stable/whatsnew/v1.0.0.html#experimental-na-scalar-to-denote-missing-values 之间的详细区别的链接)

    df.loc[df.assign(d=df.date.dt.date).duplicated(['value','ID', 'd']), 'value'] = pd.NA
    
    Out[273]:
                     date value      ID
    0 2019-01-01 00:00:00    10  Jackie
    1 2019-01-01 01:00:00  <NA>  Jackie
    2 2019-01-01 02:00:00  <NA>  Jackie
    3 2019-01-01 03:00:00  <NA>  Jackie
    4 2019-09-01 02:00:00    12    Zoop
    5 2019-09-01 03:00:00  <NA>    Zoop
    6 2019-09-01 04:00:00  <NA>    Zoop
    7 2019-09-01 05:00:00  <NA>    Zoop
    

    【讨论】:

    • 您可以使用pd.NA,因此不仅np.nan 需要导入numpy。
    • 重复值只能在同一日期删除,与频率无关。因此,如果值 10 在 1 月 1 日出现两次,在 1 月 2 日出现 3 次,则值 10 应该只在 1 月 1 日和 1 月 2 日出现一次。
    • 可能值得补充的是pd.NAnp.nan 可以有非常不同的行为。它们不一定可以互换
    • @rafaelc:添加了解释pd.NAnp.nan之间区别的链接
    • 我只是在玩pd.NA,发现在创建intsfloats 的列时,pd.NA 导致该列为object 类型。同样,pd.NA 强制将'value'type 变为object。因此,我撤回了我的建议。
    【解决方案2】:

    如果数据框已排序,这将起作用 - 如您的示例所示:

    import numpy as np                                    # to be used for np.nan
    
    df['duplicate'] = df['value'].shift(1)                # create a duplicate column 
    df['value'] = df.apply(lambda x: np.nan if x['value'] == x['duplicate'] \
                              else x['value'], axis=1)    # conditional replace
    df = df.drop('duplicate', axis=1)                     # drop helper column
    

    【讨论】:

      【解决方案3】:

      按日期分组并取第一个观察值(按时间排序时不一定是第一个),然后将结果合并回原始数据框。

      df2 = df.groupby([df['date'].dt.date, 'ID'], as_index=False).first()
      >>> df.drop(columns='value').merge(df2, on=['date', 'ID'], how='left')[df.columns]
                       date  value      ID
      0 2019-01-01 00:00:00   10.0  Jackie
      1 2019-01-01 01:00:00    NaN  Jackie
      2 2019-01-01 02:00:00    NaN  Jackie
      3 2019-01-01 03:00:00    NaN  Jackie
      4 2019-09-01 02:00:00   12.0    Zoop
      5 2019-09-01 03:00:00    NaN    Zoop
      6 2019-09-01 04:00:00    NaN    Zoop
      7 2019-09-01 05:00:00    NaN    Zoop
      

      【讨论】:

        猜你喜欢
        • 2020-12-14
        • 2022-12-01
        • 1970-01-01
        • 2021-11-20
        • 2017-08-25
        • 2017-03-20
        • 1970-01-01
        • 2016-01-08
        • 2017-08-01
        相关资源
        最近更新 更多