[python] 날짜 시간이 어떤 열인지 추론

많은 열이있는 거대한 데이터 프레임이 있으며 그중 많은 유형이 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, 잠재적으로 일부 잘못된 값 (언급은 그렇지 않으면 이후 pd.to_datetimeA의 try/ except절 할 것)? 유연한 버전과 같은 것pd.to_datetime(col)



답변

내가 볼 수있는 주요 문제는 숫자 값을 구문 분석 할 때입니다.

먼저 문자열로 변환 할 것을 제안합니다.


설정

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


답변

이 함수는 열의 값이 정규식 패턴 (\ d {4}-\ d {2}-\ d {2}) +와 일치하는 경우 열의 데이터 유형을 datetime으로 설정합니다 (예 : 2019-01-01). ). 마스크를 설정하고 적용하는 데 도움이 되는 모든 Pandas DataFrame 열 및 필터에서 문자열검색 하는 방법에 대한이 답변을 참조 하십시오.

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도움이 될 수 있습니다. 열에 날짜와 같은 값이 있으면 열이 날짜 시간이어야한다고 가정합니다. 더 빠른 다른 데이터 프레임 반복 방법을 고려하려고했습니다. Pandas의 DataFrame에서 행을 반복하는 방법에 대한이 대답 은 잘 설명했습니다.

참고 dateutil.parser없음 년 하루 값 ’12월’또는 ‘2019 11월’와 같은 임의의 문자열을 현재 하루 해 사용합니다.

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]

의 datatime 값을 사용하려는 경우 다음을 dateutil.parser추가 할 수 있습니다.

for col in list_of_datetime_columns:
    df[col] = df[col].apply(lambda x: parse_dates(x))


답변