推断哪些列是日期时间。
推断哪些列是日期时间。
我有一个非常庞大的数据框,其中包含许多列,其中许多列的类型是datetime.datetime
。问题是,许多列类型是混合类型,包括datetime.datetime
值和None
值(以及其他可能的无效值):\n
0 2017-07-06 00:00:00 1 2018-02-27 21:30:05 2 2017-04-12 00:00:00 3 2017-05-21 22:05:00 4 2018-01-22 00:00:00 ... 352867 2019-10-04 00:00:00 352868 None 352869 some_string Name: colx, Length: 352872, dtype: object
\n因此导致了一个object
类型的列。可以通过df.colx.fillna(pd.NaT)
来解决这个问题。问题是数据框太大了,无法逐个搜索列。\n另一种方法是使用pd.to_datetime(col, errors=\'coerce\')
,但是这会将包含数值的许多列转换为datetime
类型。\n我也可以使用df.fillna(float(\'nan\'), inplace=True)
,但是包含日期的列仍然是object
类型,并且仍然存在相同的问题。\n我应该采取什么方法来将那些值确实包含datetime
值的列转换为datetime
类型,但也可能包含None
和潜在的一些无效值(否则可以在try
/except
子句中使用pd.to_datetime
来实现)?类似于pd.to_datetime(col)
的灵活版本。
从上述内容中可以看出,问题出现在解析数值时。作者建议首先将数值转换为字符串,然后再进行解析。作者使用了`astype(str)`方法将DataFrame中的所有列转换为字符串,并使用`pd.to_datetime`方法将其转换为日期时间格式,同时使用`errors='coerce'`参数将无法解析的值设置为`NaT`。通过这种方式,有效地解决了问题。
原文中提到,问题出现在数值列上,因为数值列不能直接被`pd.to_datetime`解析。因此,将数值列转换为字符串是解决该问题的关键。
通过这种方法,作者成功地将原始DataFrame中的日期时间列正确解析出来,并将无法解析的值设置为`NaT`。作者对这个解决方法感到非常满意,并感谢提供帮助的人。
问题出现的原因:这个问题的出现是因为需要将一个列的数据类型设置为datetime类型,如果该列中的任何一个值与正则表达式模式(\d{4}-\d{2}-\d{2})+匹配(例如2019-01-01)。
解决方法:为了解决这个问题,可以使用一个函数来假设列中的任何日期值都表示该列的数据类型应为datetime。函数首先创建一个数据框的副本,然后使用正则表达式匹配来确定哪些列包含日期值。然后,使用pd.to_datetime方法将这些列转换为datetime类型,并将转换后的值保存回原始数据框。
文章如下:
这个函数将根据列中的任何值是否与正则表达式模式(\d{4}-\d{2}-\d{2})+匹配(例如2019-01-01),将该列的数据类型设置为datetime类型。这个函数使用了stackoverflow上的一个回答中的方法,这个回答帮助设置并应用了一个掩码,用于搜索Pandas数据框中的字符串并进行过滤。
def presume_date(dataframe): """ Set datetime by presuming any date values in the column indicates that the column data type should be datetime. Args: dataframe: Pandas dataframe. Returns: Pandas dataframe. Raises: None """ df = dataframe.copy() mask = dataframe.astype(str).apply(lambda x: x.str.match( r'(\d{4}-\d{2}-\d{2})+').any()) df_dates = df.loc[:, mask].apply(pd.to_datetime, errors='coerce') for col in df_dates.columns: df[col] = df_dates[col] return df
另一个解决方法是使用dateutil库。这个方法仍然基于一个假设,即如果一个列中有任何类似日期的值,则该列应该是datetime类型。这个方法考虑了不同的数据框迭代方法,并尝试找到更快的迭代方法。这个方法使用了stackoverflow上的一个回答,该回答很好地描述了如何在Pandas中迭代行。
import pandas as pd import datetime from dateutil.parser import parse df = pd.DataFrame(columns=['are_you_a_date','no_dates_here']) df = df.append(pd.Series({'are_you_a_date':'December 2015','no_dates_here':'just a string'}), ignore_index=True) df = df.append(pd.Series({'are_you_a_date':'February 27 2018','no_dates_here':'just a string'}), ignore_index=True) df = df.append(pd.Series({'are_you_a_date':'May 2017 12','no_dates_here':'just a string'}), ignore_index=True) df = df.append(pd.Series({'are_you_a_date':'2017-05-21','no_dates_here':'just a string'}), ignore_index=True) df = df.append(pd.Series({'are_you_a_date':None,'no_dates_here':'just a string'}), ignore_index=True) df = df.append(pd.Series({'are_you_a_date':'some_string','no_dates_here':'just a string'}), ignore_index=True) df = df.append(pd.Series({'are_you_a_date':'Processed: 2019/01/25','no_dates_here':'just a string'}), ignore_index=True) df = df.append(pd.Series({'are_you_a_date':'December','no_dates_here':'just a string'}), ignore_index=True) def parse_dates(x): try: return parse(x,fuzzy=True) except ValueError: return '' except TypeError: return '' list_of_datetime_columns = [] for row in df: if any([isinstance(parse_dates(row[0]), datetime.datetime) for row in df[[row]].values]): list_of_datetime_columns.append(row) df_dates = df.loc[:, list_of_datetime_columns].apply(pd.to_datetime, errors='coerce') for col in list_of_datetime_columns: df[col] = df_dates[col]
如果需要使用dateutil.parser中的datatime值,可以添加以下代码:
for col in list_of_datetime_columns: df[col] = df[col].apply(lambda x: parse_dates(x))
这是一个很好的想法,但不幸的是,我正在寻找一种可以推广到多种不同的datetime格式的方法,而不是硬编码格式。感谢你的努力。
没关系 - 我碰巧正在处理一个需要这个的问题。不过,我想知道是否可以将其推广到所有的日期时间格式呢?你也许需要提前考虑到你希望看到的所有格式;或者,你可能需要考虑所有你认为是有效日期时间的格式。
实际上,正如我提到的,dateutil模块似乎非常有用。
请查看我的更新答案。我使用了dateutil.parse来识别许多不同类型的日期字符串。
看起来不错!我现在没有太多时间,一会儿我会看一下。
谢谢,这很有帮助!很高兴在这里看到如何在这里使用dateutil.parse。