我有一个巨大的数据框,其中包含许多列,其中许多列的类型为datetime.datetime
。问题在于,许多还具有混合类型,例如datetime.datetime
值和None
值(以及其他可能无效的值):
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
因此会导致object
类型的列。可以使用df.colx.fillna(pd.NaT)
解决。问题在于数据框太大,无法搜索单个列。
另一种方法是使用pd.to_datetime(col, errors='coerce')
,但这将强制转换为datetime
包含数值的许多列。
尽管包含日期的列仍为df.fillna(float('nan'), inplace=True)
类型,但我仍然可以进行object
的操作,
我可以采用什么方法将那些其值确实包含datetime
值,但也可能包含None
以及可能包含一些无效值的列转换为日期时间(提及,否则将{{1} }中的pd.to_datetime
/ try
子句中)?类似于except
答案 0 :(得分:4)
如果该列中的任何值与正则表达式模式(\ d {4}-\ d {2}-\ d {2})+(例如2019- 01-01)。归功于此答案,了解如何Search for String in all Pandas DataFrame columns and filter有助于设置和应用遮罩。
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
,这可能会有所帮助。仍然在假设列中是否存在任何类似日期的值,该列应为日期时间。我试图考虑更快的其他数据框迭代方法。我认为How to iterate over rows in a DataFrame in Pandas上的答案在描述它们方面做得很好。
请注意,dateutil.parser
将对诸如'December'或'November 2019'这样的字符串使用当前日期或年份,而没有年份或日期值。
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
中的数据时间值,可以添加以下内容:
for col in list_of_datetime_columns:
df[col] = df[col].apply(lambda x: parse_dates(x))
答案 1 :(得分:1)
我看到的主要问题是解析数值时。
我建议先将它们转换为字符串
dat = {
'index': [0, 1, 2, 3, 4, 352867, 352868, 352869],
'columns': ['Mixed', 'Numeric Values', 'Strings'],
'data': [
['2017-07-06 00:00:00', 1, 'HI'],
['2018-02-27 21:30:05', 1, 'HI'],
['2017-04-12 00:00:00', 1, 'HI'],
['2017-05-21 22:05:00', 1, 'HI'],
['2018-01-22 00:00:00', 1, 'HI'],
['2019-10-04 00:00:00', 1, 'HI'],
['None', 1, 'HI'],
['some_string', 1, 'HI']
]
}
df = pd.DataFrame(**dat)
df
Mixed Numeric Values Strings
0 2017-07-06 00:00:00 1 HI
1 2018-02-27 21:30:05 1 HI
2 2017-04-12 00:00:00 1 HI
3 2017-05-21 22:05:00 1 HI
4 2018-01-22 00:00:00 1 HI
352867 2019-10-04 00:00:00 1 HI
352868 None 1 HI
352869 some_string 1 HI
df.astype(str).apply(pd.to_datetime, errors='coerce')
Mixed Numeric Values Strings
0 2017-07-06 00:00:00 NaT NaT
1 2018-02-27 21:30:05 NaT NaT
2 2017-04-12 00:00:00 NaT NaT
3 2017-05-21 22:05:00 NaT NaT
4 2018-01-22 00:00:00 NaT NaT
352867 2019-10-04 00:00:00 NaT NaT
352868 NaT NaT NaT
352869 NaT NaT NaT