【问题标题】:Elegant way to write np.where for different values in a column为列中的不同值编写 np.where 的优雅方式
【发布时间】:2021-07-09 08:26:06
【问题描述】:

我有一个如下所示的数据框

df = pd.DataFrame({'person_id': [101,101,101,101,202,202,202],
                   'person_type':['A','A','B','C','D','B','A'],
                   'login_date':['5/7/2013 09:27:00 AM','09/08/2013 11:21:00 AM','06/06/2014 08:00:00 AM','06/06/2014 05:00:00 AM','12/11/2011 10:00:00 AM','13/10/2012 12:00:00 AM','13/12/2012 11:45:00 AM'],
                   'logout_date':[np.nan,'11/08/2013 11:21:00 AM',np.nan,'06/06/2014 05:00:00 AM',np.nan,'13/10/2012 12:00:00 AM',np.nan]})
df.login_date = pd.to_datetime(df.login_date)
df.logout_date = pd.to_datetime(df.logout_date)

我想将 2 条规则应用于 logout_date

规则 1 - 如果人员类型为 BCDE AND logout_date 为 NaN,则复制登录日期值

规则 2 - 如果人员类型为 A 且 logout_date 为 NaN,则将登录日期添加 2 天

我尝试了以下

df['logout_date'] = np.where(((df['person_type'].isin(['B','C','D'])) & (df['logout_date'].isna())),df['login_date'].dt.date,df['logout_date'].dt.date)
df['logout_date'] = np.where(((df['person_type'].isin(['A'])) & (df['logout_date'].isna())),df['login_date'] + pd.DateOffset(days=2).dt.date,df['logout_date'].dt.date)

你可以看到它有多长。还有其他更好的写法吗?

我希望我的输出如下所示

person_id   person_type login_date           logout_date
101            A        2013-05-07 09:27:00  2013-05-09 09:27:00
101            A        2013-09-08 11:21:00  2013-11-08 11:21:00
101            B        2014-06-06 08:00:00  2014-06-06 08:00:00
101            C        2014-06-06 05:00:00  2014-06-06 05:00:00
202            D        2011-12-11 10:00:00  2011-12-11 10:00:00
202            B        2012-10-13 00:00:00  2012-10-13 12:00:00
202            A        2012-12-13 11:45:00  2012-12-15 11:45:00

【问题讨论】:

  • 我没有发现这两行很长。由于列寻址等原因,它看起来很长。对列使用中间变量将使行更短更清晰。
  • 如果你想要另一种写这些条件的方式,你可以看看numpy.select,但并不完全不同

标签: python python-3.x pandas dataframe pandas-groupby


【解决方案1】:

numpy.select 与 cmets 中提到的中间变量一起使用:

s = df['person_type'].fillna('missing value')
m1 = s.isin(['B','C','D', 'missing value'])
m2 = s.isin(['A','missing value'])

df['logout_date'] = np.select([m1, m2],
                              [df['login_date'], df['login_date'] + pd.DateOffset(days=2)],
                               default=df['logout_date'])

或者重写你的解决方案:

m1 = df['person_type'].isin(['B','C','D'])
m2 = df['person_type'].isin(['A'])
m3 = df['logout_date'].isna()

df['logout_date'] = np.select([m1 & m3, m2 & m3],
                              [df['login_date'], df['login_date'] + pd.DateOffset(days=2)],
                               default=df['logout_date'])

df['logout_date'] = np.select([m1 & m3, m2 & m3],
                              [df['login_date'].dt.date, 
                               (df['login_date'] + pd.DateOffset(days=2)).dt.date],
                               default=df['logout_date'].dt.date)

【讨论】:

  • @TheGreat - 最后第三个值是默认值,如果不匹配掩码列表中的任何值
  • @TheGreat 第一个值是条件列表,第二个值是匹配条件的输出列表,第三个是默认值。
  • @TheGreat - 不,因为有 2 个掩码,m1 & m3m2 & m3 所以在第二个列表中必须是 2 个输出系列 - df['login_date'].dt.date(df['login_date'] + pd.DateOffset(days=2)).dt.date
  • @TheGreat - 是的,但它是np.select
  • 我在真实数据中遇到这样的错误。知道为什么TypeError: The DTypes <class 'numpy.dtype[uint8]'> and <class 'numpy.dtype[datetime64]'> do not have a common DType. For example they cannot be stored in a single array unless the dtype is object.
猜你喜欢
  • 1970-01-01
  • 2020-09-04
  • 1970-01-01
  • 2022-10-25
  • 1970-01-01
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 2017-09-10
相关资源
最近更新 更多