Ekstrak hanya Bulan dan Tahun secara terpisah dari kolom Pandas Datetime

221

Saya memiliki Dataframe, df, dengan kolom berikut:

df['ArrivalDate'] =
...
936   2012-12-31
938   2012-12-29
965   2012-12-31
966   2012-12-31
967   2012-12-31
968   2012-12-31
969   2012-12-31
970   2012-12-29
971   2012-12-31
972   2012-12-29
973   2012-12-29
...

Elemen-elemen kolom adalah pandas.tslib.Timestamp.

Saya hanya ingin memasukkan tahun dan bulan. Saya pikir akan ada cara sederhana untuk melakukannya, tetapi saya tidak bisa mengetahuinya.

Inilah yang saya coba:

df['ArrivalDate'].resample('M', how = 'mean')

Saya mendapat kesalahan berikut:

Only valid with DatetimeIndex or PeriodIndex 

Kemudian saya mencoba:

df['ArrivalDate'].apply(lambda(x):x[:-2])

Saya mendapat kesalahan berikut:

'Timestamp' object has no attribute '__getitem__' 

Ada saran?

Sunting: Saya menemukan jawabannya.

df.index = df['ArrivalDate']

Lalu, saya bisa melakukan sampel ulang kolom lain menggunakan indeks.

Tapi saya masih ingin metode untuk mengkonfigurasi ulang seluruh kolom. Ada ide?

monkeybiz7
sumber
11
jawaban terbaik adalah jelas .. df ['mnth_yr'] = df.date_column.dt.to_ Period ('M') seperti di bawah ini dari @ jaknap32
ihightower
1
Anda bahkan tidak perlu melakukan to_period: df.date_column.dt.month(atau .year, atau .day) bekerja
elz
2
@elphz: .dt.monthkalah tahun ini. Dan .dt.to_period('M')mengubah tipe data menjadi sesuatu yang bukan datetime64 lagi. Saya akhirnya menggunakan jawaban Juan menyarankan .astype('datetime64[M]')untuk memotong nilai-nilai.
Nickolay
Bisakah Anda mengubah jawaban terbaik?
Gonzalo Garcia

Jawaban:

306

Jika Anda ingin kolom baru menampilkan tahun dan bulan secara terpisah, Anda dapat melakukan ini:

df['year'] = pd.DatetimeIndex(df['ArrivalDate']).year
df['month'] = pd.DatetimeIndex(df['ArrivalDate']).month

atau...

df['year'] = df['ArrivalDate'].dt.year
df['month'] = df['ArrivalDate'].dt.month

Kemudian Anda dapat menggabungkan mereka atau bekerja dengan mereka sebagaimana adanya.

KieranPC
sumber
7
Apakah ada cara untuk melakukan ini dalam satu baris? Saya ingin menghindari melintasi kolom yang sama beberapa kali.
fixxxer
2
Beberapa pembandingan cepat dengan timeitmenunjukkan bahwa DatetimeIndexpendekatan secara signifikan lebih cepat daripada salah satu .map/.applyatau .dt.
Snorfalorpagus
2
jawaban terbaik adalah jelas .. df ['mnth_yr'] = df.date_column.dt.to_ Period ('M') seperti di bawah ini dari @ jaknap32
ihightower
apa yang sebenarnya dilakukan pd.Datetimeindex?
JOHN
Saya kadang-kadang melakukan ini: df['date_column_trunc'] = df[date_column'].apply(lambda s: datetime.date(s.year, s.month, 1)
Stewbaca
229

Cara terbaik ditemukan !!

yang df['date_column']harus di tanggal format waktu.

df['month_year'] = df['date_column'].dt.to_period('M')

Anda juga dapat menggunakan Duntuk Hari, 2Mselama 2 Bulan dll untuk interval pengambilan sampel yang berbeda, dan jika seseorang memiliki data deret waktu dengan cap waktu, kita dapat menggunakan interval pengambilan sampel granular seperti 45Minselama 45 menit, 15Minuntuk pengambilan sampel 15 menit dll.

kabrapankaj32
sumber
8
Perhatikan bahwa kolom yang dihasilkan bukan dari jenis datetime64lagi. Menggunakan df.my_date_column.astype('datetime64[M]'), seperti pada jawaban @ Juan dikonversi ke tanggal yang mewakili hari pertama setiap bulan.
Nickolay
3
Saya terkejut ini jauh di sini.
Tim
154

Anda dapat langsung mengakses atribut yeardan month, atau meminta datetime.datetime:

In [15]: t = pandas.tslib.Timestamp.now()

In [16]: t
Out[16]: Timestamp('2014-08-05 14:49:39.643701', tz=None)

In [17]: t.to_pydatetime() #datetime method is deprecated
Out[17]: datetime.datetime(2014, 8, 5, 14, 49, 39, 643701)

In [18]: t.day
Out[18]: 5

In [19]: t.month
Out[19]: 8

In [20]: t.year
Out[20]: 2014

Satu cara untuk menggabungkan tahun dan bulan adalah dengan membuat bilangan bulat yang menyandikannya, seperti: 201408untuk Agustus 2014. Di sepanjang kolom, Anda bisa melakukan ini sebagai:

df['YearMonth'] = df['ArrivalDate'].map(lambda x: 100*x.year + x.month)

atau banyak varian daripadanya.

Saya bukan penggemar berat melakukan ini, karena hal itu membuat penyelarasan tanggal dan aritmatika menyakitkan kemudian dan terutama menyakitkan bagi orang lain yang menemukan kode atau data Anda tanpa konvensi yang sama ini. Cara yang lebih baik adalah memilih konvensi hari-bulan, seperti hari kerja akhir non-AS-liburan, atau hari pertama, dll., Dan meninggalkan data dalam format tanggal / waktu dengan konvensi tanggal yang dipilih.

The calendarModul ini berguna untuk memperoleh nilai jumlah hari tertentu seperti hari kerja akhir. Maka Anda dapat melakukan sesuatu seperti:

import calendar
import datetime
df['AdjustedDateToEndOfMonth'] = df['ArrivalDate'].map(
    lambda x: datetime.datetime(
        x.year,
        x.month,
        max(calendar.monthcalendar(x.year, x.month)[-1][:5])
    )
)

Jika Anda sedang mencari cara untuk memecahkan masalah yang lebih sederhana dengan hanya memformat kolom datetime menjadi beberapa representasi yang dirangkai, untuk itu Anda bisa memanfaatkan strftimefungsi dari datetime.datetimekelas, seperti ini:

In [5]: df
Out[5]: 
            date_time
0 2014-10-17 22:00:03

In [6]: df.date_time
Out[6]: 
0   2014-10-17 22:00:03
Name: date_time, dtype: datetime64[ns]

In [7]: df.date_time.map(lambda x: x.strftime('%Y-%m-%d'))
Out[7]: 
0    2014-10-17
Name: date_time, dtype: object
Ely
sumber
4
Performanya bisa buruk, jadi selalu baik untuk memanfaatkan fungsi pembantu sebaik mungkin, operasi vektor, dan pandasteknik split-apply-menggabungkan. Saran saya di atas tidak dimaksudkan untuk dianggap sebagai dukungan bahwa mereka adalah pendekatan yang paling berkinerja untuk kasus Anda - hanya saja itu adalah pilihan Pythonic yang valid secara gaya untuk berbagai kasus.
Ely
Jawaban di bawah oleh @KieranPC jauh lebih cepat
Ben
2
jawaban terbaiknya jelas .. df ['mnth_yr'] = df.date_column.dt.to_ Period ('M') seperti di bawah ini dari @ jaknap32
ihightower
2
Anda seharusnya mengalikan 100 dengan df['YearMonth'] = df['ArrivalDate'].map(lambda x: 1000*x.year + x.month).
Git Gud
1
@ zthomas.nc Saya pikir mereka berfungsi lebih baik sebagai dua jawaban terpisah, karena mereka menawarkan dua cara yang sangat berbeda untuk menyelesaikannya.
Ely
34

Jika Anda ingin pasangan unik tahun bulan, menggunakan berlaku cukup ramping.

df['mnth_yr'] = df['date_column'].apply(lambda x: x.strftime('%B-%Y')) 

Output bulan-tahun dalam satu kolom.

Jangan lupa untuk terlebih dahulu mengubah format tanggal-waktu sebelumnya, saya biasanya lupa.

df['date_column'] = pd.to_datetime(df['date_column'])
kabrapankaj32
sumber
Anda dapat menghindari fungsi lambda juga:df['month_year'] = df['date_column'].dt.strftime('%B-%Y')
Rishabh
13

Mengekstraksi Tahun, katakan dari ['2018-03-04']

df['Year'] = pd.DatetimeIndex(df['date']).year  

Df ['Tahun'] membuat kolom baru. Sementara jika Anda ingin mengekstrak bulan cukup gunakan. Bulan

Douglas
sumber
1
Terima kasih, Sudah sangat membantu date_1 = pd.DatetimeIndex (df ['date']) --year = date_1.year # Selama bertahun-tahun - --month = date_1.month # Selama berbulan-bulan - --dy = date_1. hari # Untuk hari--
Edwin Torres
7

Pertama-tama Anda dapat mengonversi string tanggal Anda dengan panda.to_datetime , yang memberi Anda akses ke semua datetime yang numpy dan fasilitas timedelta . Sebagai contoh:

df['ArrivalDate'] = pandas.to_datetime(df['ArrivalDate'])
df['Month'] = df['ArrivalDate'].values.astype('datetime64[M]')
Juan A. Navarro
sumber
Ini bekerja sangat baik untuk saya, karena saya sedang mencari fungsionalitas analog dengan pyspark trunc. Apakah ada dokumentasi untuk astype('datetime64[M]')konvensi?
h1-the-angsa
6

Berkat jaknap32 , saya ingin menggabungkan hasil menurut Tahun dan Bulan, jadi ini berhasil:

df_join['YearMonth'] = df_join['timestamp'].apply(lambda x:x.strftime('%Y%m'))

Outputnya rapi:

0    201108
1    201108
2    201108
Subspacian
sumber
6

Solusi @ KieranPC adalah pendekatan yang tepat untuk Pandas, tetapi tidak mudah diperluas untuk atribut yang berubah-ubah. Untuk ini, Anda dapat menggunakan getattrdalam pemahaman generator dan menggabungkan menggunakan pd.concat:

# input data
list_of_dates = ['2012-12-31', '2012-12-29', '2012-12-30']
df = pd.DataFrame({'ArrivalDate': pd.to_datetime(list_of_dates)})

# define list of attributes required    
L = ['year', 'month', 'day', 'dayofweek', 'dayofyear', 'weekofyear', 'quarter']

# define generator expression of series, one for each attribute
date_gen = (getattr(df['ArrivalDate'].dt, i).rename(i) for i in L)

# concatenate results and join to original dataframe
df = df.join(pd.concat(date_gen, axis=1))

print(df)

  ArrivalDate  year  month  day  dayofweek  dayofyear  weekofyear  quarter
0  2012-12-31  2012     12   31          0        366           1        4
1  2012-12-29  2012     12   29          5        364          52        4
2  2012-12-30  2012     12   30          6        365          52        4
jpp
sumber
1
df['year_month']=df.datetime_column.apply(lambda x: str(x)[:7])

Ini bekerja dengan baik untuk saya, tidak berpikir panda akan menafsirkan tanggal string yang dihasilkan sebagai tanggal, tetapi ketika saya melakukan plot, ia tahu betul agenda saya dan tahun_month string mana dipesan dengan benar ... panda cinta harus!

TICH
sumber
1

Ada dua langkah untuk mengekstrak tahun untuk semua kerangka data tanpa menggunakan metode yang berlaku.

Langkah 1

ubah kolom menjadi datetime:

df['ArrivalDate']=pd.to_datetime(df['ArrivalDate'], format='%Y-%m-%d')

Langkah 2

ekstrak tahun atau bulan menggunakan DatetimeIndex()metode

 pd.DatetimeIndex(df['ArrivalDate']).year
abdellah el atouani
sumber
1

SINGLE LINE: Menambahkan kolom dengan 'tahun-bulan'-pasangan: ('pd.to_datetime' pertama mengubah dtype kolom ke tanggal-waktu sebelum operasi)

df['yyyy-mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y-%m')

Maka untuk kolom 'tahun' atau 'bulan' tambahan:

df['yyyy'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y')

df['mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%m')
Matthi9000
sumber