构建一个csv文件:
import pandas as pd
pd.DataFrame(data={"datetime": ["1999-10-10 10:10:10"] * 150, "index": range(150)}).to_csv('/tmp/test.csv', index=False)
查看/tmp/test.csv
内容:
datetime,index
1999-10-10 10:10:10,0
1999-10-10 10:10:10,1
1999-10-10 10:10:10,2
1999-10-10 10:10:10,3
...
读取这个csv文件:
df = pd.read_csv('/tmp/test.csv')
print(df.dtypes)
输出:
datetime object
index int64
dtype: object
默认pandas并不会自动做日期类型数据的识别,datatime被识别成字符串, 使用pandas自带的推断日期方法进行推断:
df = pd.read_csv('/tmp/test.csv', infer_datetime_format=True, parse_dates=['datetime'])
print(df.dtypes)
输出:
datetime datetime64[ns]
index int64
dtype: object
这种方法的问题在于需要事先知道列名,指定从哪些列里面推断这些列是不是日期类型,而期望pandas自动识别哪些是日期列就像识别哪些是float列一样。
查看一下pandas的推断方法:
infer_datetime_format: bool, default False
If True andparse_dates
is True for a column, try to infer the
datetime format based on the first datetime string. If the format
can be inferred, there often will be a large parsing speed-up.
它的推断方式使用第一个不为空的值尝试转换为日期列,如果能成功把此列当成日期列处理,否则不是。
仿照这个思路,可以来实现自动识别哪些是日期列:
- 正常读取pd.read_csv()
- 读取出来的df挑出来是object类型的列
- 对object类型的列取前100行非空的行,尝试转换成日期,如果全部成功则认为该列是日期类型
这个方法的优势:
- 不需要事先知道csv数据中的列
- 使用前100行数据比前1行数据更靠谱,而且性能损失不大
实现参考:
df = pd.read_csv('/tmp/test.csv')
def get_categorical_cols(df: pd.DataFrame):
c_list = []
for k, v in df.dtypes.items():
if 'object' in v.name:
c_list.append(k)
return c_list
def parse_date(series: pd.Series):
format = "%Y-%m-%d %H:%M:%S" # Now only support one format
# 1. take top 100 non-empty values
INFER_TOP_N = 100
series_non_empty = series.dropna()[: INFER_TOP_N]
# 2. if these value all datetime value infer it as datetime nor object
for item in series_non_empty:
try:
if isinstance(item, str):
pd.datetime.strptime(item, format)
else:
return series
except Exception as e:
return series
# 3. infer as datetime
return pd.to_datetime(series, format=format)
categorical_cols = get_categorical_cols(df)
for c in categorical_cols:
df[c] = parse_date(df[c])
print(df.dtypes)
输出:
datetime datetime64[ns]
index int64
dtype: object
参考: