【问题标题】:How to convert columns into one datetime column in pandas?如何在熊猫中将列转换为一个日期时间列?
【发布时间】:2013-10-21 11:05:18
【问题描述】:

我有一个数据框,其中前 3 列是“MONTH”、“DAY”、“YEAR”

每一列都有一个整数。 有没有一种 Pythonic 方法可以在数据框中将所有三列都转换为日期时间?

发件人:

M    D    Y    Apples   Oranges
5    6  1990      12        3
5    7  1990      14        4
5    8  1990      15       34
5    9  1990      23       21

进入:

Datetimes    Apples   Oranges
1990-6-5        12        3
1990-7-5        14        4
1990-8-5        15       34
1990-9-5        23       21

【问题讨论】:

    标签: python pandas datetime


    【解决方案1】:

    在 0.13 中(即将推出),这是经过高度优化且速度非常快(但在 0.12 中仍然非常快);两个数量级都比循环快

    In [3]: df
    Out[3]: 
       M  D     Y  Apples  Oranges
    0  5  6  1990      12        3
    1  5  7  1990      14        4
    2  5  8  1990      15       34
    3  5  9  1990      23       21
    
    In [4]: df.dtypes
    Out[4]: 
    M          int64
    D          int64
    Y          int64
    Apples     int64
    Oranges    int64
    dtype: object
    
    # in 0.12, use this
    In [5]: pd.to_datetime((df.Y*10000+df.M*100+df.D).apply(str),format='%Y%m%d')
    
    # in 0.13 the above or this will work
    In [5]: pd.to_datetime(df.Y*10000+df.M*100+df.D,format='%Y%m%d')
    Out[5]: 
    0   1990-05-06 00:00:00
    1   1990-05-07 00:00:00
    2   1990-05-08 00:00:00
    3   1990-05-09 00:00:00
    dtype: datetime64[ns]
    

    【讨论】:

    • 谢谢,它成功了,你能解释一下*10000和*100的目的是什么吗?没关系,目的是将 2011, 5, 3, 转换为易于阅读的 20110503。谢谢!!
    • 是的 - 这实际上是最快的方法,因为这些是矢量化数字运算,并且转换为日期时间不会通过字符串往返
    • 我很想看看你是否从pd.to_datetime(dict(year=df.Y, month=df.M, day=df.D))得到更好的结果
    • @holdenweb:根据%timeit,它们大致相同 - 在我使用的数据集上,数字版本可能快 5-10%。我将使用 dict 版本,因为它更具可读性。
    【解决方案2】:

    我重新解决了这个问题,我认为我找到了解决方案。我通过以下方式初始化了csv文件:

    pandas_object = DataFrame(read_csv('/Path/to/csv/file', parse_dates=True, index_col = [2,0,1] ))
    

    在哪里:

    index_col = [2,0,1]
    

    表示[年、月、日]的列

    现在唯一的问题是我现在有了三个新的索引列,一个代表年份,另一个代表月份,另一个代表日期。

    【讨论】:

    • 试试parse_dates=[[2,0,1]](注意双括号。以read_csv 上的文档字符串为例。
    【解决方案3】:

    这是使用NumPy datetime64 and timedelta64 arithmetic 的替代方法。小型 DataFrame 似乎要快一些,而大型 DataFrame 则要快得多:

    import numpy as np
    import pandas as pd
    
    df = pd.DataFrame({'M':[1,2,3,4], 'D':[6,7,8,9], 'Y':[1990,1991,1992,1993]})
    #    D  M     Y
    # 0  6  1  1990
    # 1  7  2  1991
    # 2  8  3  1992
    # 3  9  4  1993
    
    y = np.array(df['Y']-1970, dtype='<M8[Y]')
    m = np.array(df['M']-1, dtype='<m8[M]')
    d = np.array(df['D']-1, dtype='<m8[D]')
    dates2 = pd.Series(y+m+d)
    # 0   1990-01-06
    # 1   1991-02-07
    # 2   1992-03-08
    # 3   1993-04-09
    # dtype: datetime64[ns]
    

    In [214]: df = pd.concat([df]*1000)
    
    In [215]: %timeit pd.to_datetime((df['Y']*10000+df['M']*100+df['D']).astype('int'), format='%Y%m%d')
    100 loops, best of 3: 4.87 ms per loop
    
    In [216]: %timeit pd.Series(np.array(df['Y']-1970, dtype='<M8[Y]')+np.array(df['M']-1, dtype='<m8[M]')+np.array(df['D']-1, dtype='<m8[D]'))
    1000 loops, best of 3: 839 µs per loop
    

    这里有一个帮助函数可以使它更容易使用:

    def combine64(years, months=1, days=1, weeks=None, hours=None, minutes=None,
                  seconds=None, milliseconds=None, microseconds=None, nanoseconds=None):
        years = np.asarray(years) - 1970
        months = np.asarray(months) - 1
        days = np.asarray(days) - 1
        types = ('<M8[Y]', '<m8[M]', '<m8[D]', '<m8[W]', '<m8[h]',
                 '<m8[m]', '<m8[s]', '<m8[ms]', '<m8[us]', '<m8[ns]')
        vals = (years, months, days, weeks, hours, minutes, seconds,
                milliseconds, microseconds, nanoseconds)
        return sum(np.asarray(v, dtype=t) for t, v in zip(types, vals)
                   if v is not None)
    
    In [437]: combine64(df['Y'], df['M'], df['D'])
    Out[437]: array(['1990-01-06', '1991-02-07', '1992-03-08', '1993-04-09'], dtype='datetime64[D]')
    

    【讨论】:

    • 我认为这个,或者至少这个功能,对 pandas 来说是一个很好的增强。我们应该只是想出一个 API。
    • 是的,不得不做*10000-1970 这样的事情是愚蠢的。我们绝对应该能够以更简单的方式组合标准时间类型。 (如果有更好的方法但我们都不知道,那么至少有一个文档错误..)
    【解决方案4】:

    将数据框转换为字符串以便于字符串连接:

    df=df.astype(str)
    

    然后转换为日期时间,指定格式:

    df.index=pd.to_datetime(df.Y+df.M+df.D,format="%Y%m%d")
    

    替换索引而不是创建新列。

    【讨论】:

      【解决方案5】:

      假设您有一本字典foo,其中每一列日期是平行的。如果是这样,这是你的一个班轮:

      >>> from datetime import datetime
      >>> foo = {"M": [1,2,3], "D":[30,30,21], "Y":[1980,1981,1982]}
      >>>
      >>> df = pd.DataFrame({"Datetime": [datetime(y,m,d) for y,m,d in zip(foo["Y"],foo["M"],foo["D"])]})
      

      它的真正胆量是这一点:

      >>> [datetime(y,m,d) for y,m,d in zip(foo["Y"],foo["M"],foo["D"])]
      [datetime.datetime(1980, 1, 30, 0, 0), datetime.datetime(1981, 2, 28, 0, 0), datetime.datetime(1982, 3, 21, 0, 0)]
      

      zip 就是为此而生的。它采用并行列表并将它们转换为元组。然后他们通过那里的列表理解将元组解包(for y,m,d in 位),然后输入datetime 对象构造函数。

      pandas 似乎对日期时间对象很满意。

      【讨论】:

        【解决方案6】:

        0.18.1 版本中,您可以使用to_datetime,但是:

        • 列的名称必须是yearmonthdayhourminutesecond
        • 最小列是yearmonthday

        示例:

        import pandas as pd
        
        df = pd.DataFrame({'year': [2015, 2016],
                           'month': [2, 3],
                            'day': [4, 5],
                            'hour': [2, 3],
                            'minute': [10, 30],
                            'second': [21,25]})
        
        print df
           day  hour  minute  month  second  year
        0    4     2      10      2      21  2015
        1    5     3      30      3      25  2016
        
        print pd.to_datetime(df[['year', 'month', 'day']])
        0   2015-02-04
        1   2016-03-05
        dtype: datetime64[ns]
        
        print pd.to_datetime(df[['year', 'month', 'day', 'hour']])
        0   2015-02-04 02:00:00
        1   2016-03-05 03:00:00
        dtype: datetime64[ns]
        
        print pd.to_datetime(df[['year', 'month', 'day', 'hour', 'minute']])
        0   2015-02-04 02:10:00
        1   2016-03-05 03:30:00
        dtype: datetime64[ns]
        
        print pd.to_datetime(df)
        0   2015-02-04 02:10:21
        1   2016-03-05 03:30:25
        dtype: datetime64[ns]
        

        另一种解决方案是转换为dictionary

        print df
           M  D     Y  Apples  Oranges
        0  5  6  1990      12        3
        1  5  7  1990      14        4
        2  5  8  1990      15       34
        3  5  9  1990      23       21
        
        print pd.to_datetime(dict(year=df.Y, month=df.M, day=df.D))
        0   1990-05-06
        1   1990-05-07
        2   1990-05-08
        3   1990-05-09
        dtype: datetime64[ns]
        

        【讨论】:

        • 甚至(稍微)比建议的更快,因为我们甚至放弃了最小的算术,感谢 jezrael!
        • 抛开性能讨论不谈,我发现转换为dict 是最容易理解的。
        【解决方案7】:
         [pd.to_datetime(str(a)+str(b)+str(c),
                         format='%m%d%Y'
                        ) for a,b,c in zip(df.M, df.D, df.Y)]
        

        【讨论】:

          【解决方案8】:

          更好的方法如下:

          import pandas as pd
          
          import datetime
          
          dataset = pd.read_csv('dataset.csv')
          
          date=dataset.apply(lambda x: datetime.date(int(x['Yr']), x['Mo'], x['Dy']),axis=1)
          
          date = pd.to_datetime(date)
          
          dataset = dataset.drop(columns=['Yr', 'Mo', 'Dy'])
          
          dataset.insert(0, 'Date', date)
          
          dataset.head()
          

          【讨论】:

          • 请在此代码中添加一些描述或 cmets。
          猜你喜欢
          • 2019-02-17
          • 2018-12-08
          • 2017-08-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多