どの列が日時であるかを推測する


14

多くの列を持つ巨大なデータフレームがあり、その多くはタイプ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型へのキャストに従うことができるどのようなアプローチで、その値が実際に含まれていないこれらの列datetimeの値を、だけでなく、含まれている可能性がありNone、かつ潜在的にいくつかの不正な値(言及は、そうでないので、pd.to_datetimetry/ except句が行うだろうか)?の柔軟なバージョンのようなものpd.to_datetime(col)


オブジェクトは、データフレームの種類に格納されていますdatetime.datetimepandas._libs.tslibs.timestamps.Timestamp?前者の場合、日時を作成したものをpandas少し処理しやすいタイプに変更することをお勧めします。
ALollz

あるNone実際、あなたの列にNoneその文字列または代表者は?
Erfan、

彼らはNone、文字列ではありません。潜在的に誤った値も存在する可能性があります... @erfan
yatu

3
次に、データベース内のSQLモデルはどのようになっているのでしょうか。sqlは特定のタイプの列を強制するため。どのようにして混合型のカラムになりましたか?あなたは多分も持つ列を示すことができるdatetimevalues、それには?
Erfan、

1
dateutilパーサーを使用して日時を推測します。列にいくつかの(たとえば5つの日付)のしきい値を設定して、stackoverflow.com
Serge

回答:


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

まあ、これは問題を非常に単純化するだけのようです。私も考えていませんでした。理想的なシナリオは、単純に適用することでpd.to_datetimeありcoerce、エラーは多数あります。問題は数値列にありました。しかし、文字列にキャストされた数値列がパンダによって解析されないことは私には起こりませんでしたto_datetime。どうもありがとう、これは本当に役に立ちます!
yatu 2019年

4

この関数は、列のいずれかの値が正規表現パターン(\ d {4}-\ d {2}-\ d {2})+に一致する場合、列のデータ型を日時に設定します(例: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は、「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]

のdatatime値も使用するdateutil.parser場合は、これを追加できます。

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

これは良いアイデアですが、残念ながら、フォーマットをハードコーディングせずに、いくつかの異なる日時フォーマットに一般化できるものを探しています。努力に感謝
yatu

@yatu問題ありません-私はたまたまこれを必要とする何かに取り組んでいます。しかし、すべての日時形式に一般化できるかどうか疑問に思いますか?表示されると予想されるすべての形式を事前に考慮する必要がある場合があります。または、有効な日時と見なすすべての形式。
はい、これはリック

@yatu実際にはdateutil、@ Sergeによって言及されたモジュールは、有用であるように見えます。
はい、これはリック

@yatu私の更新された答えを見てください。以前dateutil.parseは、さまざまな種類の日付文字列を識別していました。
はい、これはリック

いいね!今はあまり時間がないので、できるだけ早く見ていきましょう。@ yes
yatu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.