【发布时间】:2014-09-18 15:30:17
【问题描述】:
我有这个问题的解决方案,实际上有 2 个解决方案,但我对它们不满意。原因是我试图读取的文件有大约 1200 万行,并且使用这些解决方案需要花费大量时间来处理它们。主要是解决方案是逐行操作。
所以,我是这样读取文件的:
In [1]: df = pd.read_csv('C:/Projects/NPMRDS/FHWA_TASK2-4_NJ_09_2013_TT.CSV')
df.head()
Out [1]: TMC DATE EPOCH Travel_TIME_ALL_VEHICLES Travel_TIME_PASSENGER_VEHICLES Travel_TIME_FREIGHT_TRUCKS
0 103N04152 9252013 211 12 12 NaN
1 103N04152 9262013 0 7 7 NaN
2 103N04152 9032013 177 8 8 NaN
3 103N04152 9042013 176 8 9 7
我的问题在于 DATE 和 EPOCH 列。我想将它们合并到一个日期时间列中。
- DATE 采用“%m%d%Y”格式(缺少前导零)
-
EPOCH 是一天的 5 分钟纪元:
Time EPOCH 00:00:00 => 0 00:05:00 => 1 ... ... 12:00:00 => 144 12:05:00 => 145 ... ... 23:50:00 => 286 23:55:00 => 287
我想要的是这样的:
In [2]: df.head()
Out [2]: TMC DATE_TIME DATE EPOCH Travel_TIME_ALL_VEHICLES Travel_TIME_PASSENGER_VEHICLES Travel_TIME_FREIGHT_TRUCKS
0 103N04152 2013-09-25 17:35:00 9252013 211 12 12 NaN
1 103N04152 2013-09-26 00:00:00 9262013 0 7 7 NaN
2 103N04152 2013-09-03 14:45:00 9032013 177 8 8 NaN
3 103N04152 2013-09-04 14:30:00 9042013 176 8 9 7
现在,我可以通过执行以下三件事中的任何一项来逐行执行此操作:
In [3]: df = pd.read_csv('C:/Projects/NPMRDS/FHWA_TASK2-4_NJ_09_2013_TT.CSV',
converters={'DATE': lambda x: datetime.datetime.strptime(x, '%m%d%Y'),
'EPOCH': lambda x: str(datetime.timedelta(minutes = int(x)*5))},
parse_dates = {'date_time': ['DATE', 'EPOCH']},
keep_date_col = True)
df.head()
Out [3]: date_time TMC DATE EPOCH Travel_TIME_ALL_VEHICLES Travel_TIME_PASSENGER_VEHICLES Travel_TIME_FREIGHT_TRUCKS
0 2013-09-25 17:35:00 103N04152 2013-09-25 17:35:00 12 12 NaN
1 2013-09-26 00:00:00 103N04152 2013-09-26 00:00:00 7 7 NaN
2 2013-09-03 14:45:00 103N04152 2013-09-03 14:45:00 8 8 NaN
3 2013-09-04 14:40:00 103N04152 2013-09-04 14:40:00 8 9 7
4 2013-09-05 09:35:00 103N04152 2013-09-05 09:35:00 10 10 NaN
在这种方法中,我丢失了 DATE 和 EPOCH 的原始格式,但它并不会真正影响对数据帧的进一步计算。我可以使用 date_parser,而不是使用 converters 作为参数。或者,在读取数据后,类似于第 1 行,我可以这样做:
In [4]: df = pd.read_csv('C:/Projects/NPMRDS/FHWA_TASK2-4_NJ_09_2013_TT.CSV')
df['date_time'] = pd.to_datetime([datetime.datetime.strptime(str(df['DATE'][x]), '%m%d%Y') + datetime.timedelta(minutes = int(df['EPOCH'][x]*5)) for x in range(len(df))])
df.head()
Out [4]: TMC DATE EPOCH Travel_TIME_ALL_VEHICLES Travel_TIME_PASSENGER_VEHICLES Travel_TIME_FREIGHT_TRUCKS DATE_TIME
0 103N04152 9252013 211 12 12 NaN 2013-09-25 17:35:00
1 103N04152 9262013 0 7 7 NaN 2013-09-26 00:00:00
2 103N04152 9032013 177 8 8 NaN 2013-09-03 14:45:00
3 103N04152 9042013 176 8 9 7 2013-09-04 14:40:00
4 103N04152 9052013 115 10 10 NaN 2013-09-05 09:35:00
一个更理想的结果(不用担心列的顺序),但仍然是逐行的,并且需要大量的时间。
然后是pandas.to_datetime和pandas.to_timedelta,运行速度比上面介绍的方法快很多。但是如果不求助于字符串函数,我就无法将结果合并在一起,这些函数又主要是逐行的。
有谁知道更好的方法吗?
编辑:解决方案!!!
除了chrisb's 回答之外,我也找到了一种方法。诀窍在于将pandas.to_datetime() 中的box 参数设置为False。像这样:
df['DATE_TIME'] = pd.to_datetime(df['DATE'], format='%m%d%Y', box=False) + pd.to_timedelta(df['EPOCH']*5*60, unit='s')
将其设置为 False 会返回一个 numpy.datetime[64] 数组,而不是 pandas.DatetimeIndex。更多信息可以在pandas.to_datetime() 文档中找到。而且,pandas.to_timedelta() 不适用于 unit='m'。
【问题讨论】:
标签: python datetime python-3.x pandas