Bisakah panda secara otomatis mengenali tanggal?

151

Hari ini saya sangat terkejut dengan fakta bahwa saat membaca data dari file data (misalnya) panda mampu mengenali jenis nilai:

df = pandas.read_csv('test.dat', delimiter=r"\s+", names=['col1','col2','col3'])

Misalnya itu dapat diperiksa dengan cara ini:

for i, r in df.iterrows():
    print type(r['col1']), type(r['col2']), type(r['col3'])

Khususnya bilangan bulat, pelampung dan string dikenali dengan benar. Namun, saya memiliki kolom yang memiliki tanggal dalam format berikut: 2013-6-4. Tanggal-tanggal ini dikenali sebagai string (bukan sebagai objek-tanggal python). Apakah ada cara untuk "mempelajari" panda hingga tanggal yang dikenali?

Roma
sumber
Harap selalu nyatakan versi panda, untuk jenis pertanyaan yang tergantung pada versi ini. Pada Juli 2013, ini akan menjadi v0.11
smci
Dan dtypes diperbaiki untuk setiap kolom, Anda tidak perlu mengulanginya df.iterrows()dan melihatnya untuk setiap baris, lakukan df.info()sekali saja.
smci

Jawaban:

327

Anda harus menambahkan parse_dates=True, atau parse_dates=['column name']ketika membaca, itu biasanya cukup untuk menguraikannya secara ajaib. Tetapi selalu ada format aneh yang perlu didefinisikan secara manual. Dalam kasus seperti itu, Anda juga dapat menambahkan fungsi pengurai tanggal, yang merupakan cara paling fleksibel.

Misalkan Anda memiliki kolom 'datetime' dengan string Anda, maka:

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)

Dengan cara ini Anda bahkan dapat menggabungkan beberapa kolom ke dalam kolom datetime tunggal, ini menggabungkan kolom 'tanggal' dan 'waktu' ke dalam kolom 'datetime' tunggal:

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)

Anda dapat menemukan arahan (yaitu huruf-huruf yang akan digunakan untuk format yang berbeda) untuk strptimedan strftime di halaman ini .

Kassi Rutger
sumber
8
Tidak bekerja untuk saya, saya mendapatkan kesalahan berikut:TypeError: strptime() argument 1 must be str, not float
Jean Paul
6
Saya mendapatkan kesalahan ini karena ada nan dalam bingkai data saya.
Jean Paul
Anda dapat menambahkan item yang juga NaTs bahan non-parsable atau NaN atau / Ns. karena sepertinya parser ini benar-benar melewatkan seluruh kolom jika ada yang seperti itu
Amir
Ada opsi infer_datetime_format: "panda akan berusaha menyimpulkan format string datetime di kolom". Ini bisa digunakan sebagai ganti date_parser.
Menangkan dan
1
Perhatikan bahwa jika tanggal Anda dalam ISO 8601format Anda tidak boleh lewat infer_datetime_formatatau fungsi parser - ini jauh lebih lambat daripada membiarkan panda menanganinya (terutama yang terakhir). Format tanggal dalam jawaban ini juga termasuk dalam kategori ini
Mr_and_Mrs_D
20

Mungkin antarmuka panda telah berubah sejak @Rutger menjawab, tetapi dalam versi yang saya gunakan (0.15.2), date_parserfungsi tersebut menerima daftar tanggal alih-alih nilai tunggal. Dalam hal ini, kodenya harus diperbarui seperti ini:

dateparse = lambda dates: [pd.datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in dates]

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)
Sean
sumber
11

Metode read_csv panda bagus untuk tanggal parsing. Dokumentasi lengkap di http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

Anda bahkan dapat memiliki bagian tanggal yang berbeda di kolom yang berbeda dan meneruskan parameter:

parse_dates : boolean, list of ints or names, list of lists, or dict
If True -> try parsing the index. If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a
separate date column. If [[1, 3]] -> combine columns 1 and 3 and parse as a single date
column. {‘foo : [1, 3]} -> parse columns 1, 3 as date and call result foo

Penginderaan default dari tanggal bekerja dengan baik, tetapi tampaknya bias terhadap format tanggal Amerika utara. Jika Anda tinggal di tempat lain, Anda terkadang ketahuan dengan hasilnya. Sejauh yang saya ingat 1/6/2000 berarti 6 Januari di AS dibandingkan 1 Juni tempat saya tinggal. Cukup cerdas untuk mengayunkannya jika tanggal seperti 23/6/2000 digunakan. Mungkin lebih aman untuk tetap dengan variasi tanggal YYYYMMDD sekalipun. Permintaan maaf kepada pengembang panda, di sini tetapi saya belum mengujinya dengan tanggal lokal baru-baru ini.

Anda dapat menggunakan parameter date_parser untuk melewatkan fungsi untuk mengonversi format Anda.

date_parser : function
Function to use for converting a sequence of string columns to an array of datetime
instances. The default uses dateutil.parser.parser to do the conversion.
Joop
sumber
2
Anda dapat menentukan dayfirstBenar untuk tanggal Eropa / internasional. pandas.pydata.org/pandas-docs/stable/generated/…
Will Gordon
10

Anda dapat menggunakan pandas.to_datetime()seperti yang direkomendasikan dalam dokumentasi untuk pandas.read_csv():

Jika kolom atau indeks berisi tanggal yang tidak dapat dihapus, seluruh kolom atau indeks akan dikembalikan tanpa diubah sebagai tipe data objek. Untuk parsing datetime non-standar, gunakan pd.to_datetimesetelah pd.read_csv.

Demo:

>>> D = {'date': '2013-6-4'}
>>> df = pd.DataFrame(D, index=[0])
>>> df
       date
0  2013-6-4
>>> df.dtypes
date    object
dtype: object
>>> df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d')
>>> df
        date
0 2013-06-04
>>> df.dtypes
date    datetime64[ns]
dtype: object
Eugene Yarmash
sumber
itu mengkonversi kolom lain untuk tanggal juga, yang merupakan tipe objek
ratnesh
10

Ketika menggabungkan dua kolom menjadi kolom datetime tunggal, jawaban yang diterima menghasilkan kesalahan (versi panda 0.20.3), karena kolom dikirim ke fungsi date_parser secara terpisah.

Karya-karya berikut:

def dateparse(d,t):
    dt = d + " " + t
    return pd.datetime.strptime(dt, '%d/%m/%Y %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)
Aku adalah si walrus
sumber
1
Saya menggunakan panda 0,22 dan setuju bahwa jawaban yang diterima tidak lagi berfungsi.
Dai
Ini menciptakan "TypeError: hanya dapat menggabungkan str (bukan" float ") ke str" untuk saya. Kolom tanggal adalah d / m / y dan kolom waktu adalah H: M: 00
IceQueeny
8

Ya - sesuai dengan pandas.read_csv dokumentasi :

Catatan: Ada jalur cepat untuk tanggal yang diformat iso8601 .

Jadi jika csv Anda memiliki nama kolom datetimedan tanggalnya seperti 2013-01-01T01:01misalnya, menjalankan ini akan membuat panda (saya di v0.19.2) mengambil tanggal dan waktu secara otomatis:

df = pd.read_csv('test.csv', parse_dates=['datetime'])

Perhatikan bahwa Anda harus lulus secara eksplisit parse_dates, itu tidak berfungsi tanpa.

Verifikasi dengan:

df.dtypes

Anda harus melihat tipe data dari kolom tersebut datetime64[ns]

Gaurav
sumber
Saya pikir Anda salah paham pertanyaannya. Pengguna ingin tahu apakah opsi dapat diaktifkan untuk format string-nya.
Arya McCarthy
@AryaMcCarthy umm, dia pada dasarnya ingin tanggalnya dikenali dengan benar, jadi saya menyebutkan bagaimana dia bisa mengubah sumber data sehingga secara alami dikenali oleh panda. Dia tidak menyebutkan di mana pun dia tidak bisa mengubah format data sumber.
Gaurav
1

Jika kinerja penting bagi Anda, pastikan waktu Anda:

import sys
import timeit
import pandas as pd

print('Python %s on %s' % (sys.version, sys.platform))
print('Pandas version %s' % pd.__version__)

repeat = 3
numbers = 100

def time(statement, _setup=None):
    print (min(
        timeit.Timer(statement, setup=_setup or setup).repeat(
            repeat, numbers)))

print("Format %m/%d/%y")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,07/29/15
x2,07/29/15
x3,07/29/15
x4,07/30/15
x5,07/29/15
x6,07/29/15
x7,07/29/15
y7,08/05/15
x8,08/05/15
z3,08/05/15
''' * 100)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%m/%d/%y")); data.seek(0)')

print("Format %Y-%m-%d %H:%M:%S")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,2016-10-15 00:00:43
x2,2016-10-15 00:00:56
x3,2016-10-15 00:00:56
x4,2016-10-15 00:00:12
x5,2016-10-15 00:00:34
x6,2016-10-15 00:00:55
x7,2016-10-15 00:00:06
y7,2016-10-15 00:00:01
x8,2016-10-15 00:00:00
z3,2016-10-15 00:00:02
''' * 1000)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")); data.seek(0)')

cetakan:

Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28) 
[Clang 6.0 (clang-600.0.57)] on darwin
Pandas version 0.23.4
Format %m/%d/%y
0.19123052499999993
8.20691274
8.143124389
1.2384357139999977
Format %Y-%m-%d %H:%M:%S
0.5238807110000039
0.9202787830000005
0.9832778819999959
12.002349824999996

Jadi dengan tanggal yang diformat iso8601 ( %Y-%m-%d %H:%M:%Stampaknya tanggal yang diformat iso8601, saya kira T dapat dijatuhkan dan diganti dengan spasi) Anda tidak boleh menentukan infer_datetime_format(yang tidak membuat perbedaan dengan yang lebih umum baik tampaknya) dan melewati Anda sendiri parser hanya dalam kinerja melumpuhkan. Di sisi lain, date_parsertidak membuat perbedaan dengan format hari tidak begitu standar. Pastikan waktu sebelum Anda mengoptimalkan, seperti biasa.

Mr_and_Mrs_D
sumber
1

Saat memuat file csv berisi kolom tanggal. Kami memiliki dua pendekatan untuk membuat panda untuk mengenali kolom tanggal yaitu

  1. Pandas secara eksplisit mengenali format dengan arg date_parser=mydateparser

  2. Pandas secara implisit mengenali format oleh agr infer_datetime_format=True

Beberapa data kolom tanggal

01/01/18

01/02/18

Di sini kita tidak tahu dua hal pertama. Mungkin bulan atau hari. Jadi dalam hal ini kita harus menggunakan Metode 1: - Secara eksplisit lulus format

    mydateparser = lambda x: pd.datetime.strptime(x, "%m/%d/%y")
    df = pd.read_csv(file_name, parse_dates=['date_col_name'],
date_parser=mydateparser)

Metode 2: - Secara implisit atau secara otomatis mengenali format

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
kamran kausar
sumber