1. 程式人生 > 實用技巧 >pandas自動推斷日期型別

pandas自動推斷日期型別

構建一個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 and parse_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.

它的推斷方式使用第一個不為空的值嘗試轉換為日期列,如果能成功把此列當成日期列處理,否則不是。

仿照這個思路,可以來實現自動識別哪些是日期列:

  1. 正常讀取pd.read_csv()
  2. 讀取出來的df挑出來是object型別的列
  3. 對object型別的列取前100行非空的行,嘗試轉換成日期,如果全部成功則認為該列是日期型別

這個方法的優勢:

  1. 不需要事先知道csv資料中的列
  2. 使用前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

參考: