Pilih kolom mana yang merupakan datetime

14

Saya memiliki kerangka data yang besar dengan banyak kolom, banyak di antaranya bertipe datetime.datetime. Masalahnya adalah bahwa banyak juga yang memiliki tipe campuran, termasuk misalnya datetime.datetimenilai dan Nonenilai (dan berpotensi nilai tidak valid lainnya):

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

Karenanya menghasilkan objectkolom tipe. Ini bisa diselesaikan dengan df.colx.fillna(pd.NaT). Masalahnya adalah bahwa kerangka data terlalu besar untuk mencari kolom individual.

Pendekatan lain adalah menggunakan pd.to_datetime(col, errors='coerce'), namun ini akan dilemparkan ke datetimebanyak kolom yang berisi nilai numerik.

Saya juga bisa melakukannya df.fillna(float('nan'), inplace=True), meskipun kolom yang berisi tanggal masih objectbertipe, dan masih akan memiliki masalah yang sama.

Pendekatan apa yang bisa saya ikuti untuk melemparkan ke datetime kolom-kolom yang nilainya benar-benar berisi datetimenilai-nilai, tetapi juga bisa mengandung None, dan berpotensi beberapa nilai yang tidak valid (menyebutkan karena kalau tidak pd.to_datetimedalam a try/ exceptklausa akan lakukan)? Sesuatu seperti versi fleksibelpd.to_datetime(col)

yatu
sumber
Apakah objek disimpan dalam tipe DataFrame datetime.datetimeatau pandas._libs.tslibs.timestamps.Timestamp? Jika mantan rekomendasi saya akan mengubah apa pun yang menciptakan datetime ke jenis yang pandasmenangani sedikit lebih baik.
ALollz
Apakah Nonedi kolom Anda, aktual Noneatau string perwakilannya?
Erfan
Mereka Nonebukan string. Nilai yang berpotensi salah juga ... @erfan
yatu
3
Lalu saya bertanya-tanya, bagaimana model sql dalam database Anda? Karena sql memaksa jenis kolom tertentu. Bagaimana Anda bisa menghasilkan kolom tipe campuran? Bisakah Anda juga menampilkan kolom yang memiliki datetimedan valuesdi dalamnya?
Erfan
1
gunakan parser dateutil untuk menebak datetime. Dapat menetapkan ambang beberapa (misalnya 5 tanggal) di kolom untuk memastikan stackoverflow.com/questions/9507648/…
Serge

Jawaban:

1

Masalah utama yang saya lihat adalah ketika mem-parsing nilai numerik.

Saya akan mengusulkan untuk mengubahnya menjadi string terlebih dahulu


Mendirikan

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

Larutan

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
piRquared
sumber
Yah sepertinya ini sangat menyederhanakan masalah. Aku bahkan tidak memikirkan ini. Skenario yang ideal adalah hanya menerapkan pd.to_datetimedan coercekesalahan, karena ada banyak. Masalahnya dengan kolom numerik. Tetapi tidak terpikir oleh saya bahwa kolom numerik yang dilemparkan ke string tidak diuraikan oleh panda ' to_datetime. Terima kasih banyak, ini sangat membantu!
yatu
4

Fungsi ini akan mengatur tipe data kolom ke datetime, jika ada nilai dalam kolom yang cocok dengan pola regex (\ d {4} - \ d {2} - \ d {2}) + (mis. 2019-01-01 ). Terima kasih atas jawaban ini tentang cara Mencari String di semua kolom dan filter PandF DataFrame yang membantu pengaturan dan penerapan mask.

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

Bekerja dari saran untuk digunakan dateutil, ini dapat membantu. Masih bekerja pada anggapan bahwa jika ada nilai seperti tanggal dalam kolom, bahwa kolom harus menjadi datetime. Saya mencoba mempertimbangkan berbagai metode iterasi dataframe yang lebih cepat. Saya pikir jawaban ini tentang Bagaimana cara mengulangi baris dalam DataFrame di Pandas melakukan pekerjaan dengan baik menggambarkan mereka.

Perhatikan bahwa dateutil.parserakan menggunakan hari atau tahun saat ini untuk string seperti 'Desember' atau 'November 2019' tanpa nilai tahun atau hari.

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]

Jika Anda juga ingin menggunakan nilai datatime dari dateutil.parser, Anda dapat menambahkan ini:

for col in list_of_datetime_columns:
    df[col] = df[col].apply(lambda x: parse_dates(x))
Ya ini Rick
sumber
Ini adalah ide yang bagus, tapi sayangnya saya sedang mencari sesuatu yang dapat digeneralisasi ke beberapa format datetime yang berbeda, jadi tanpa hardcoding format. Hargai upaya itu
yatu
@Yatu Bukan masalah - Saya kebetulan mengerjakan sesuatu yang membutuhkan ini. Saya ingin tahu apakah Anda dapat menyamaratakan semua format datetime? Anda mungkin harus memperhitungkan dulu semua format yang Anda harapkan untuk dilihat; atau, semua format yang Anda anggap sebagai datetime yang valid.
Ya ini Rick
@yatu Sebenarnya dateutilmodul yang disebutkan oleh @Serge itu sepertinya bisa berguna.
Ya ini Rick
@yatu silakan lihat jawaban saya yang diperbarui. Saya biasa dateutil.parsemengidentifikasi berbagai jenis string tanggal.
Ya ini Rick
Kelihatan bagus! tidak punya banyak waktu sekarang, akan kita lihat secepat aku bisa @yes
yatu