【问题标题】:Avoiding nested .apply()避免嵌套 .apply()
【发布时间】:2021-04-16 15:03:50
【问题描述】:

我正在处理由同一天/日期的不同时间组成的数据集。不同的时间代表给定事件的发生。除了时间之外,日期在另一列中给出(更多详细信息请参见下面的数据 sn-p)。

为了进一步处理数据,我需要将不同的时间与日期结合起来以获得完整的日期时间时间戳。幸运的是,我能够通过实现嵌套的.apply() 调用来实现所需的输出,如下所示:

import io

import pandas as pd


DATA_STRING = """
date        event_1     event_2     event_3  
2019-12-16  14:01:00    14:27:00    14:47:00
2020-01-16  13:47:00    14:08:00    14:28:00
2020-01-20  12:02:00    12:23:00    12:42:00
"""

TIME_COLUMNS = ['event_1', 'event_2', 'event_3']


def combine_timestamp(row):
    date = row['date']
    times = row[TIME_COLUMNS]
    return times.apply(lambda t: pd.Timestamp.combine(date, t.time()))


file_like = io.StringIO(DATA_STRING)
df = pd.read_csv(file_like, sep='\s+')

df['date'] = pd.to_datetime(df['date'])
df[TIME_COLUMNS] = df[TIME_COLUMNS].apply(pd.to_datetime)
# --> timestamps with date set to today (not a problem as time is relevant only)

df[TIME_COLUMNS] = df.apply(combine_timestamp, axis='columns')

print(df)

印刷:

        date             event_1             event_2             event_3
0 2019-12-16 2019-12-16 14:01:00 2019-12-16 14:27:00 2019-12-16 14:47:00
1 2020-01-16 2020-01-16 13:47:00 2020-01-16 14:08:00 2020-01-16 14:28:00
2 2020-01-20 2020-01-20 12:02:00 2020-01-20 12:23:00 2020-01-20 12:42:00

但是,我想知道是否有更优雅的方式来实现这一点并避免这些嵌套的 .apply()` 调用。

【问题讨论】:

    标签: python pandas datetime apply


    【解决方案1】:

    我可以想到这样的事情:将日期与事件列添加为字符串,然后转换为日期时间:

    df = pd.read_csv(file_like, sep='\s+')
    out = df.assign(**(df['date'].add(' ').to_numpy()[:,None] + df.filter(like='event')))
    out = out.apply(pd.to_datetime)
    

    print(out)
    
             date             event_1             event_2             event_3
    0  2019-12-16 2019-12-16 14:01:00 2019-12-16 14:27:00 2019-12-16 14:47:00
    1  2020-01-16 2020-01-16 13:47:00 2020-01-16 14:08:00 2020-01-16 14:28:00
    2  2020-01-20 2020-01-20 12:02:00 2020-01-20 12:23:00 2020-01-20 12:42:00
    

    【讨论】:

    • 感谢您的方法。然而,这引发了TypeError: unsupported operand type(s) for +: 'DatetimeArray' and 'str'。在 Python 3.7.4 中使用 pandas 1.2.4 和 numpy 1.20.2。
    • @albert 不要先转换为日期时间,看我的代码我没有使用df[TIME_COLUMNS] = df[TIME_COLUMNS].apply(pd.to_datetime)这一行,所以添加字符串然后一次性转换为日期时间
    • 有没有办法处理作为日期时间对象给出的数据?前期处理已经依赖于此。我是否应该将日期时间对象转换为其字符串表示形式?
    • @albert 如果date 已经是日期时间,那么@albert 或QuangHoang 的第二个解决方案应该可以工作,只需在他们的解决方案中将.add(pd.to_datetime(df.date), axis=0) 替换为.add(df['date'], axis=0)
    【解决方案2】:

    使用可以占用整列的pd.to_datetime

    (df.filter(like='event').add(df.date, axis=0)
       .apply(pd.to_datetime,format='%H:%M:%S%Y-%m-%d')
    )
    

    另一种方式是pd.to_timedelta 表示时间,pd.to_datetime 表示日期:

    (df.filter(like='event')
       .apply(pd.to_timedelta)
       .add(pd.to_datetime(df.date), axis=0)
    )
    

    输出:

                  event_1             event_2             event_3
    0 2019-12-16 14:01:00 2019-12-16 14:27:00 2019-12-16 14:47:00
    1 2020-01-16 13:47:00 2020-01-16 14:08:00 2020-01-16 14:28:00
    2 2020-01-20 12:02:00 2020-01-20 12:23:00 2020-01-20 12:42:00
    

    【讨论】:

      猜你喜欢
      • 2019-11-30
      • 2011-02-16
      • 2016-11-19
      • 2014-08-23
      • 2018-10-07
      • 2023-01-30
      • 1970-01-01
      • 2019-03-24
      • 1970-01-01
      相关资源
      最近更新 更多