在pandas/python中高效解析时间格式

2024-05-15 22:11:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个如下的数据帧

+-----------+------+--------------+
| invoiceNo | time | invoiceValue |
+-----------+------+--------------+
|     A     |   6  |       2      |
+-----------+------+--------------+
|     B     |  12  |       3      |
+-----------+------+--------------+
|     C     |  356 |       5      |
+-----------+------+--------------+
|     D     | 2145 |       6      |
+-----------+------+--------------+

df = pd.DataFrame({'invoiceNo':['A','B','C','D'],
             'time':[6,12,356,2145],
             'invoiceValue':[2,3,5,6] })

我的任务是从time值中提取相应的hour

然而,问题是,理想情况下,time列应该显示4位。但是,由于数字格式的原因,它去掉了前导零。因此,这里的6表示0006,即00 hour&06 minutes

为了实现这一点,我编写了下面的代码,它工作得非常好

df['adj-time'] = df['time'].apply(lambda x: '{0:0>4}'.format(x))
df['adj-time'] = df['adj-time'].apply(lambda x: pd.to_datetime(x,format= '%H%M'))
df['hour'] = df['adj-time'].apply(lambda x: x.hour)
df.drop('adj-time',axis=1, inplace=True)

下面是我想要的输出

+-----------+------+--------------+------+
| invoiceNo | time | invoiceValue | hour |
+-----------+------+--------------+------+
|     A     |   6  |       2      |   0  |
+-----------+------+--------------+------+
|     B     |  12  |       3      |   0  |
+-----------+------+--------------+------+
|     C     |  356 |       5      |   3  |
+-----------+------+--------------+------+
|     D     | 2145 |       6      |  21  |
+-----------+------+--------------+------+

然而,我的问题是,对于大型数据集,上面的代码是very very slowtime consuming

如何提高性能/速度方面的效率


Tags: 数据lambda代码formatdataframedftimevery
3条回答

如果时间是整数,则:

hour = int(time/100)

如果是字符串:

hour = int(int(time)/100)
  • 也使用zfill
  • 'time'设置为字符串,转换为日期时间并提取小时组件
df['hour'] = pd.to_datetime(df.time.astype('str').str.zfill(4), format='%H%M').dt.hour

# display(df)
  invoiceNo  time  invoiceValue  hour
0         A     6             2     0
1         B    12             3     0
2         C   356             5     3
3         D  2145             6    21

从csv读取

  • 在中读取数据时设置'time'列的类型,这样就不需要.astype('str')
df = pd.read_csv('test.csv', dtype={'time': str})
df['hour'] = pd.to_datetime(df.time.str.zfill(4), format='%H%M').dt.hour

timeit测试

# 2M rows of data
df = pd.DataFrame({'time':[6,12,356,2145]})
dft = pd.concat([df] * 500000).reset_index(drop=True)

%%timeit
pd.to_datetime(dft.time.astype('str').str.zfill(4), format='%H%M').dt.hour
[out]:
1.51 s ± 23.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
pd.to_numeric(dft.time.astype(str).str.zfill(4).str[0:2])
[out]:
2.6 s ± 41.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

使用字符串操作提取小时数zfill最多4个字符(如果还有秒,则为6个),然后对前2个字符进行切片以获得小时数(分钟为[2:4],秒为[4:6])。使用pd.to_numeric获取数字数据类型

df['hour'] = pd.to_numeric(df['time'].astype(str).str.zfill(4).str[0:2])
df['minutes'] = pd.to_numeric(df['time'].astype(str).str.zfill(4).str[2:4])

  invoiceNo  time  invoiceValue  hour  minutes
0         A     6             2     0        6
1         B    12             3     0       12
2         C   356             5     3       56
3         D  2145             6    21       45

如果您有兴趣将'time'转换为timedelta64[ns]数据类型,您可以使用pd.to_datetime的灵活解析。由于缺少年/月/日,因此默认值为1900-01-01,我们将其减去

df['new_time'] = (pd.to_datetime(df['time'].astype(str).str.zfill(4), format='%H%M')
                  - pd.to_datetime('1900-01-01'))

  invoiceNo  time  invoiceValue  hour  minutes        new_time
0         A     6             2     0        6 0 days 00:06:00
1         B    12             3     0       12 0 days 00:12:00
2         C   356             5     3       56 0 days 03:56:00
3         D  2145             6    21       45 0 days 21:45:00

相关问题 更多 >