将 pandas 列转换为 datetime64,包括缺失值

Posted

技术标签:

【中文标题】将 pandas 列转换为 datetime64,包括缺失值【英文标题】:Converting pandas columns to datetime64 including missing values 【发布时间】:2014-01-08 11:16:17 【问题描述】:

使用 Pandas 处理一些基于时间序列的数据,包括日期、数字、类别等。

我遇到的问题是让 pandas 从 CSV 创建的 DataFrame 中正确处理我的日期/时间列。我的数据中有 18 个日期列,它们不是连续的,原始 CSV 中的未知值的字符串值为“未知”。某些列的所有单元格中都包含有效的日期时间,并且可以通过 pandas read_csv 方法正确地猜出它们的 dtype。但是,在特定数据样本中,有些列的所有单元格都为“未知”,并且这些单元格被键入为对象。

我加载 CSV 的代码如下:

self.datecols = ['Claim Date', 'Lock Date', 'Closed Date', 'Service Date', 'Latest_Submission', 'Statement Date 1', 'Statement Date 2', 'Statement Date 3', 'Patient Payment Date 1', 'Patient Payment Date 2', 'Patient Payment Date 3', 'Primary 1 Payment Date', 'Primary 2 Payment Date', 'Primary 3 Payment Date', 'Secondary 1 Payment Date', 'Secondary 2 Payment Date', 'Tertiary Payment Date']
self.csvbear = pd.read_csv(file_path, index_col="Claim ID", parse_dates=True, na_values=['Unknown'])
self.csvbear = pd.DataFrame.convert_objects(self.csvbear, convert_dates='coerce')
print self.csvbear.dtypes
print self.csvbear['Tertiary Payment Date'].values

print self.csvbear.dtypes 的输出

Prac                            object
Doctor Name                     object
Practice Name                   object
Specialty                       object
Speciality Code                  int64
Claim Date              datetime64[ns]
Lock Date               datetime64[ns]
Progress Note Locked            object
Aging by Claim Date              int64
Aging by Lock Date               int64
Closed Date             datetime64[ns]
Service Date            datetime64[ns]
Week Number                      int64
Month                   datetime64[ns]
Current Insurance               object
...
Secondary 2 Deductible        float64
Secondary 2 Co Insurance      float64
Secondary 2 Member Balance    float64
Secondary 2 Paid              float64
Secondary 2 Witheld           float64
Secondary 2 Ins                object
Tertiary Payment Date          object
Tertiary Payment ID           float64
Tertiary Allowed              float64
Tertiary Deductible           float64
Tertiary Co Insurance         float64
Tertiary Member Balance       float64
Tertiary Paid                 float64
Tertiary Witheld              float64
Tertiary Ins                  float64
Length: 96, dtype: object
[nan nan nan ..., nan nan nan]
Press any key to continue . . .

如您所见,第三次付款日期 col 应该是 datetime64 dtype,但它只是一个对象,它的实际内容只是 NaN(从字符串 'Unknown' 的 read_csv 函数放在那里)。

如何可靠地将所有日期列转换为将 datetime64 作为 dtype 并将 NaT 用于“未知”单元格?

【问题讨论】:

【参考方案1】:

如果你有一个 all-nan 列,它不会被read_csv 正确强制。最简单的就是这样做(如果一列已经是 datetime64[ns] 就会通过)。

In [3]: df = DataFrame(dict(A = Timestamp('20130101'), B = np.random.randn(5), C = np.nan))

In [4]: df
Out[4]: 
                    A         B   C
0 2013-01-01 00:00:00 -0.859994 NaN
1 2013-01-01 00:00:00 -2.562136 NaN
2 2013-01-01 00:00:00  0.410673 NaN
3 2013-01-01 00:00:00  0.480578 NaN
4 2013-01-01 00:00:00  0.464771 NaN

[5 rows x 3 columns]

In [5]: df.dtypes
Out[5]: 
A    datetime64[ns]
B           float64
C           float64
dtype: object

In [6]: df['A'] = pd.to_datetime(df['A'])

In [7]: df['C'] = pd.to_datetime(df['C'])

In [8]: df
Out[8]: 
                    A         B   C
0 2013-01-01 00:00:00 -0.859994 NaT
1 2013-01-01 00:00:00 -2.562136 NaT
2 2013-01-01 00:00:00  0.410673 NaT
3 2013-01-01 00:00:00  0.480578 NaT
4 2013-01-01 00:00:00  0.464771 NaT

[5 rows x 3 columns]

In [9]: df.dtypes
Out[9]: 
A    datetime64[ns]
B           float64
C    datetime64[ns]
dtype: object

convert_objects 不会强制将列转换为日期时间,除非它至少有 1 个非 nan 事物是日期(这就是您的示例失败的原因)。 to_datetime 可以更具侵略性,因为它“知道”你真的想要转换它。

【讨论】:

仅供参考,如果您有嵌入的非日期,您可能需要将coerce=True 传递给to_datetime(并且您希望它们转换为NaT 嗯,它似乎不需要它,因为 read_csv 强制已经为日期 cols 生成了所有数据,而不是 NaN 的日期。不过感谢您的提醒。【参考方案2】:

我喜欢你使用DataFrame.convert_objects 的方法,比我之前尝试过的方法优雅得多。

查看 API 文档:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

parse_dates : 布尔值、整数或名称列表、列表列表或字典

如果为真 -> 尝试解析索引。如果 [1, 2, 3] -> 尝试将第 1、2、3 列分别解析为单独的日期列。如果 [[1, 3]] -> 合并第 1 列和第 3 列并解析为单个日期列。 ‘foo’ : [1, 3] -> 将第 1、3 列解析为日期并调用结果‘foo’

我认为您现在正处于分析的数据整理阶段。格式化数据以使其成为正确的格式通常是分析中最长的部分。有些事情表现不佳,因此有必要针对特殊情况对这些事情进行硬编码。

因此,既然您知道哪些列没有正确解析,我建议您回到代码中,并在 read_csv 阶段解析这些列。这是一个建议:

self.csvbear = pd.read_csv(file_path, index_col="Claim ID", parse_dates=[column, numbers, go, here], na_values=['Unknown'])

您会注意到parse_dates=True 已更改为parse_dates=[column, numbers, go, here]。对于行为不正常的列,这可能是到达您需要的位置的最快的蛮力方法。

【讨论】:

以上是关于将 pandas 列转换为 datetime64,包括缺失值的主要内容,如果未能解决你的问题,请参考以下文章

将 float64 列转换为 datetime pandas 时出错

将 datetime64[ns] 索引转换为日期 pandas 以进行比较

如何从 pandas.DatetimeIndex 转换为 numpy.datetime64?

熊猫 datetime64 到字符串

将 pandas 系列的 dtype <- 'datetime64' 转换为 dtype <- 'np.int' 而无需迭代

将 Pandas DataFrame 中的日期对象列转换为字符串