Pandas日期时间格式化

3

是否可以表示带有零后缀的pd.to_datetime?似乎零被删除了。

print pd.to_datetime("2000-07-26 14:21:00.00000",
                format="%Y-%m-%d %H:%M:%S.%f")

结果是

2000-07-26 14:21:00

期望的结果是:
2000-07-26 14:21:00.00000

我知道这些值的意思相同,但保持一致会更好。

你能否发布你的输出结果,因为这可能只是一个显示问题。 - EdChum
2个回答

2
进行一些测试表明,使用格式“%H:%M:%S.%f”格式化日期时间数据时,如果小数点后第九位数字非零,则%f能够提供纳秒级分辨率。当格式化字符串时,根据小数点后最不重要的数字的位置以及它是否也是最后一个数字,会添加从零到五个不等的尾随零。以下是从测试数据中得出的表格,其中position表示最不重要的非零数字和最后一个数字的位置,zeros表示格式化时添加的尾随零的数量:
    position zeros
       9      0
       8      1
       7      2
       6      0
       5      1
       4      2
       3      3
       2      4
       1      5

当一个列以"%H:%M:%S.%f"的格式整体格式化时,所有元素都将具有相同数量的小数位数,这可以通过添加或删除尾随零来完成,即使这样会增加或减少原始数据的分辨率。我猜这样做的原因是一致性和美学上的考虑,通常不会引入过多的误差,因为在数字计算中,尾随零通常不会影响立即结果,但它们可能会影响其误差的估计以及如何呈现它们(Trailing ZerosRules for Significant Figures)。
以下是应用"%H:%M:%S.%f"格式到单个字符串和pandas.Series(DataFrame列),并使用pandas.to_datetime将其应用于DataFrame中可转换为datetime的列,并应用pandas.DataFrame.convert_objects(convert_dates ='coerce')到DataFrames的一些观察结果。
在字符串上,pandas在时间转换中保留了最多九个小数位中的非零数字,并在未提供日期时添加了日期:
import pandas as pd
pd.to_datetime ("10:00:00.000000001",format="%H:%M:%S.%f")
Out[15]: Timestamp('1900-01-01 10:00:00.000000001')

pd.to_datetime ("2015-09-17 10:00:00.000000001",format="%Y-%m-%d %H:%M:%S.%f")
Out[15]: Timestamp('2015-09-17 10:00:00.000000001')

在此之前,对于最终非零数字为最后一位的测试,它会在最后一个非零数字后面添加五个尾随零,增加原始数据的分辨率,除非最后一个非零数字位于小数点右侧六位。
pd.to_datetime ("10:00:00.00000001",format="%H:%M:%S.%f")
Out[15]: Timestamp('1900-01-01 10:00:00.000000010')

pd.to_datetime ("2015-09-17 10:00:00.00000001",format="%Y-%m-%d %H:%M:%S.%f")
Out[16]: Timestamp('2015-09-17 10:00:00.000000010')

pd.to_datetime ("10:00:00.0000001",format="%H:%M:%S.%f")
Out[15]: Timestamp('1900-01-01 10:00:00.000000100')

pd.to_datetime ("2015-09-17 10:00:00.0000001",format="%Y-%m-%d %H:%M:%S.%f")
Out[17]: Timestamp('2015-09-17 10:00:00.000000100')

pd.to_datetime ("10:00:00.000001",format="%H:%M:%S.%f")
Out[33]: Timestamp('1900-01-01 10:00:00.000001')

pd.to_datetime ("2015-09-17 10:00:00.000001",format="%Y-%m-%d %H:%M:%S.%f")
Out[18]: Timestamp('2015-09-17 10:00:00.000001')

pd.to_datetime ("10:00:00.00001",format="%H:%M:%S.%f")
Out[6]: Timestamp('1900-01-01 10:00:00.000010')

pd.to_datetime ("2015-09-17 10:00:00.00001",format="%Y-%m-%d %H:%M:%S.%f")
Out[19]: Timestamp('2015-09-17 10:00:00.000010')

pd.to_datetime ("10:00:00.0001",format="%H:%M:%S.%f")
Out[9]: Timestamp('1900-01-01 10:00:00.000100')

pd.to_datetime ("2015-09-17 10:00:00.0001",format="%Y-%m-%d %H:%M:%S.%f")
Out[21]: Timestamp('2015-09-17 10:00:00.000100')

pd.to_datetime ("10:00:00.001",format="%H:%M:%S.%f")
Out[10]: Timestamp('1900-01-01 10:00:00.001000')

pd.to_datetime ("2015-09-17 10:00:00.001",format="%Y-%m-%d %H:%M:%S.%f")
Out[22]: Timestamp('2015-09-17 10:00:00.001000')

pd.to_datetime ("10:00:00.01",format="%H:%M:%S.%f")
Out[12]: Timestamp('1900-01-01 10:00:00.010000')

pd.to_datetime ("2015-09-17 10:00:00.01",format="%Y-%m-%d %H:%M:%S.%f")
Out[24]: Timestamp('2015-09-17 10:00:00.010000'

pd.to_datetime ("10:00:00.1",format="%H:%M:%S.%f")
Out[13]: Timestamp('1900-01-01 10:00:00.100000')

pd.to_datetime ("2015-09-17 10:00:00.1",format="%Y-%m-%d %H:%M:%S.%f")
Out[26]: Timestamp('2015-09-17 10:00:00.100000')

让我们看看如何在DataFrame中使用它:
!type test.csv # here type is Windows substitute for Linux cat command
date,mesg
10:00:00.000000001,one
10:00:00.00000001,two
10:00:00.0000001,three
10:00:00.000001,four
10:00:00.00001,five
10:00:00.0001,six
10:00:00.001,seven
10:00:00.01,eight
10:00:00.1,nine
10:00:00.000000001,ten
10:00:00.000000002,eleven
10:00:00.000000003,twelve

df = pd.read_csv('test.csv')
df
Out[30]: 
                  date    mesg
0   10:00:00.000000001     one
1    10:00:00.00000001     two
2     10:00:00.0000001   three
3      10:00:00.000001    four
4       10:00:00.00001    five
5        10:00:00.0001     six
6         10:00:00.001   seven
7          10:00:00.01   eight
8           10:00:00.1    nine
9   10:00:00.000000001     ten
10  10:00:00.000000002  eleven
11  10:00:00.000000003  twelve

df.dtypes
Out[31]: 
date    object
mesg    object
dtype: object

使用convert_objects对DataFrame进行日期时间转换,它没有格式选项,即使某些原始数据的分辨率低于或高于微秒,也会提供微秒分辨率,并添加今天的日期:
df2 = df.convert_objects(convert_dates='coerce')
df2
Out[32]: 
                     date    mesg
0  2015-09-17 10:00:00.000000     one
1  2015-09-17 10:00:00.000000     two
2  2015-09-17 10:00:00.000000   three
3  2015-09-17 10:00:00.000001    four
4  2015-09-17 10:00:00.000010    five
5  2015-09-17 10:00:00.000100     six
6  2015-09-17 10:00:00.001000   seven
7  2015-09-17 10:00:00.010000   eight
8  2015-09-17 10:00:00.100000    nine
9  2015-09-17 10:00:00.000000     ten
10 2015-09-17 10:00:00.000000  eleven
11 2015-09-17 10:00:00.000000  twelve

df2.dtypes
Out[33]: 
date    datetime64[ns]
mesg            object
dtype: object

从原始数据创建的DataFrame列中,某些具有高于微秒分辨率的元素值的更大分辨率不能在没有显式格式说明符(即使用DataFrame.convert_objects完成日期时间转换)进行datetime转换后通过“%H:%M:%S。 %f”格式化来恢复。
df2['date'] = pd.to_datetime(df2['date'],format="%H:%M:%S.%f")
df2
Out[34]: 
                         date    mesg
0  2015-09-17 10:00:00.000000     one
1  2015-09-17 10:00:00.000000     two
2  2015-09-17 10:00:00.000000   three
3  2015-09-17 10:00:00.000001    four
4  2015-09-17 10:00:00.000010    five
5  2015-09-17 10:00:00.000100     six
6  2015-09-17 10:00:00.001000   seven
7  2015-09-17 10:00:00.010000   eight
8  2015-09-17 10:00:00.100000    nine
9  2015-09-17 10:00:00.000000     ten
10 2015-09-17 10:00:00.000000  eleven
11 2015-09-17 10:00:00.000000  twelve

在将DataFrame列格式化为“%H:%M:%S.%f”之前进行日期时间转换,如果至少有一个元素在第九个位置上具有非零数字(如pandas.to_datetime documentation中所宣传的),则可以提供纳秒分辨率,但也会将分辨率小于纳秒的原始数据提高到该级别,并添加1900-01-01作为日期。
df3 = df.copy(deep=True)
df3['date'] = pd.to_datetime(df3['date'],format="%H:%M:%S.%f",coerce=True)
df3
Out[35]:
                            date    mesg
0  1900-01-01 10:00:00.000000001     one
1  1900-01-01 10:00:00.000000010     two
2  1900-01-01 10:00:00.000000100   three
3  1900-01-01 10:00:00.000001000    four
4  1900-01-01 10:00:00.000010000    five
5  1900-01-01 10:00:00.000100000     six
6  1900-01-01 10:00:00.001000000   seven
7  1900-01-01 10:00:00.010000000   eight
8  1900-01-01 10:00:00.100000000    nine
9  1900-01-01 10:00:00.000000001     ten
10 1900-01-01 10:00:00.000000002  eleven
11 1900-01-01 10:00:00.000000003  twelve

使用“%H:%M:%S。%f”格式化DataFrame列会在小数点后最低有效数字处添加零(整个列中都添加零,根据上面的零位置表添加),并将所有其他数据的分辨率与之对齐,即使这样做会增加或减少一些原始数据的分辨率。
df4 = pd.read_csv('test2.csv')
df4
Out[36]: 
                  date    mesg
0   10:00:00.000000000     one
1    10:00:00.00000000     two
2     10:00:00.0000000   three
3      10:00:00.000000    four
4       10:00:00.00000    five
5        10:00:00.0001     six
6          10:00:00.00   seven
7           10:00:00.0   eight
8            10:00:00.    nine
9   10:00:00.000000000     ten
10  10:00:00.000000000  eleven
11   10:00:00.00000000  twelve

df4['date'] = pd.to_datetime(df4['date'],format="%H:%M:%S.%f",coerce=True)
df4
Out[37]: 
                         date    mesg
0  1900-01-01 10:00:00.000000     one
1  1900-01-01 10:00:00.000000     two
2  1900-01-01 10:00:00.000000   three
3  1900-01-01 10:00:00.000000    four
4  1900-01-01 10:00:00.000000    five
5  1900-01-01 10:00:00.000100     six
6  1900-01-01 10:00:00.000000   seven
7  1900-01-01 10:00:00.000000   eight
8                         NaT    nine # nothing after decimal point in raw data
9  1900-01-01 10:00:00.000000     ten
10 1900-01-01 10:00:00.000000  eleven
11 1900-01-01 10:00:00.000000  twelve

尝试使用包含日期的日期列相同的DataFrame时,发生了同样的事情:
df25
Out[38]: 
                             date    mesg
0   2015-09-10 10:00:00.000000000     one
1    2015-09-11 10:00:00.00000000     two
2     2015-09-12 10:00:00.0000000   three
3      2015-09-13 10:00:00.000000    four
4       2015-09-14 10:00:00.00000    five
5        2015-09-15 10:00:00.0001     six
6          2015-09-16 10:00:00.00   seven
7           2015-09-17 10:00:00.0   eight
8            2015-09-18 10:00:00.    nine
9   2015-09-19 10:00:00.000000000     ten
10  2015-09-20 10:00:00.000000000  eleven
11   2015-09-21 10:00:00.00000000  twelve

df25['date'] = pd.to_datetime(df25['date'],format="%Y-%m-%d %H:%M:%S.%f",coerce=True)
df25
Out[39]: 
                         date    mesg
0  2015-09-10 10:00:00.000000     one
1  2015-09-11 10:00:00.000000     two
2  2015-09-12 10:00:00.000000   three
3  2015-09-13 10:00:00.000000    four
4  2015-09-14 10:00:00.000000    five
5  2015-09-15 10:00:00.000100     six
6  2015-09-16 10:00:00.000000   seven
7  2015-09-17 10:00:00.000000   eight
8                         NaT    nine # nothing after decimal point in raw data
9  2015-09-19 10:00:00.000000     ten
10 2015-09-20 10:00:00.000000  eleven
11 2015-09-21 10:00:00.000000  twelve

当原始数据小数点后没有非零有效数字时,使用 DataFrame 列“%H:%M:%S。%f”进行格式化可能会统一为所有数据提供两个小数点后的零,即使这会增加或降低某些原始数据的分辨率:
df5 = pd.read_csv('test3.csv')
df5
Out[40]: 
                  date    mesg
0         10:00:00.000     one
1           10:00:00.0     two
2         10:00:00.000   three
3         10:00:00.000    four
4          10:00:00.00    five
5         10:00:00.000     six
6          10:00:00.00   seven
7           10:00:00.0   eight
8           10:00:00.0    nine
9   10:00:00.000000000     ten
10        10:00:00.000  eleven
11        10:00:00.000  twelve

df5['date'] = pd.to_datetime(df5['date'],format="%H:%M:%S.%f",coerce=True)
df5
Out[41]: 
                  date    mesg
0  1900-01-01 10:00:00     one
1  1900-01-01 10:00:00     two
2  1900-01-01 10:00:00   three
3  1900-01-01 10:00:00    four
4  1900-01-01 10:00:00    five
5  1900-01-01 10:00:00     six
6  1900-01-01 10:00:00   seven
7  1900-01-01 10:00:00   eight
8  1900-01-01 10:00:00    nine
9  1900-01-01 10:00:00     ten
10 1900-01-01 10:00:00  eleven
11 1900-01-01 10:00:00  twelve

在将包含日期的DataFrame进行此测试时,发生了与之前相同的情况:
df45
Out[42]: 
                             date    mesg
0         2015-09-10 10:00:00.000     one
1           2015-09-11 10:00:00.0     two
2         2015-09-12 10:00:00.000   three
3         2015-09-13 10:00:00.000    four
4          2015-09-14 10:00:00.00    five
5         2015-09-15 10:00:00.000     six
6          2015-09-16 10:00:00.00   seven
7           2015-09-17 10:00:00.0   eight
8           2015-09-18 10:00:00.0    nine
9   2015-09-19 10:00:00.000000000     ten
10        2015-09-20 10:00:00.000  eleven
11        2015-09-21 10:00:00.000  twelve

df45['date'] = pd.to_datetime(df45['date'],format="%Y-%m-%d %H:%M:    %S.%f",coerce=True)
df45
Out[43]: 
                  date    mesg
0  2015-09-10 10:00:00     one
1  2015-09-11 10:00:00     two
2  2015-09-12 10:00:00   three
3  2015-09-13 10:00:00    four
4  2015-09-14 10:00:00    five
5  2015-09-15 10:00:00     six
6  2015-09-16 10:00:00   seven
7  2015-09-17 10:00:00   eight
8  2015-09-18 10:00:00    nine
9  2015-09-19 10:00:00     ten
10 2015-09-20 10:00:00  eleven
11 2015-09-21 10:00:00  twelve

0

抱歉,我的声望不够高,无法评论,所以我只能在这里尝试回答。完全同意EdChum的观点,这是一个显示问题。如果你尝试:

pd.to_datetime ("10:00:00.00001",format="%H:%M:%S.%f")

响应应该是:

Timestamp('1900-01-01 10:00:00.000010')


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接