pandasで日付・時間の列を処理(文字列変換、年月日抽出など)
pandas.DataFrame
の日時(日付・時間)を表した列を操作する方法を説明する。文字列とdatetime64[ns]
型との相互変換、年月日、時刻を数値として抽出する方法など。
以下の内容について説明する。
- 文字列を
datetime64[ns]
型(Timestamp
型)に変換:to_datetime()
Timestamp
型の属性・メソッドdt
アクセサで列全体を一括処理- 年月日、曜日などを抽出
- 任意のフォーマットで日時を文字列に変換
- Pythonの
dataframe
型、NumPyのdatetime64[ns]
型の配列に変換 dt
に用意されていないメソッドの場合
DatetimeIndex
の場合- ファイルからの読み込み時に文字列を
datetime64[ns]
型に変換
datetime64[ns]
型をインデックスに指定し、時系列データとして処理する方法およびその活用法は以下の記事を参照。
以下のcsvファイルを読み込んだpandas.DataFrame
を例とする。なお、datetime
は説明のためにインポートしているだけなので、処理自体には不要。
import pandas as pd
import datetime
df = pd.read_csv('data/src/sample_datetime_multi.csv')
print(df)
# A B
# 0 2017-11-01 12:24 2017年11月1日 12時24分
# 1 2017-11-18 23:00 2017年11月18日 23時00分
# 2 2017-12-05 5:05 2017年12月5日 5時05分
# 3 2017-12-22 8:54 2017年12月22日 8時54分
# 4 2018-01-08 14:20 2018年1月8日 14時20分
# 5 2018-01-19 20:01 2018年1月19日 20時01分
いずれの列もobject
型(各要素は文字列str
型)。
print(df.dtypes)
# A object
# B object
# dtype: object
print(type(df['A'][0]))
# <class 'str'>
文字列をdatetime64[ns]型(Timestamp型)に変換: to_datetime()
pandas.to_datetime()
関数を使うと、日時(日付・時間)を表した文字列の列pandas.Series
をdatetime64[ns]
型に変換できる。
print(pd.to_datetime(df['A']))
# 0 2017-11-01 12:24:00
# 1 2017-11-18 23:00:00
# 2 2017-12-05 05:05:00
# 3 2017-12-22 08:54:00
# 4 2018-01-08 14:20:00
# 5 2018-01-19 20:01:00
# Name: A, dtype: datetime64[ns]
標準的な書式でない場合は、引数format
に書式文字列を指定する。使用できる書式化コードは以下の公式ドキュメントを参照。
print(pd.to_datetime(df['B'], format='%Y年%m月%d日 %H時%M分'))
# 0 2017-11-01 12:24:00
# 1 2017-11-18 23:00:00
# 2 2017-12-05 05:05:00
# 3 2017-12-22 08:54:00
# 4 2018-01-08 14:20:00
# 5 2018-01-19 20:01:00
# Name: B, dtype: datetime64[ns]
元の書式が違っていても指し示す日時が同じであればdatetime64[ns]
型の値は等価。
print(pd.to_datetime(df['A']) == pd.to_datetime(df['B'], format='%Y年%m月%d日 %H時%M分'))
# 0 True
# 1 True
# 2 True
# 3 True
# 4 True
# 5 True
# dtype: bool
datetime64[ns]
型に変換した列をpandas.DataFrame
に新たな列として追加したい場合は、新たな列名を指定して代入すればよい。元の列名を指定すると上書きされる。
df['X'] = pd.to_datetime(df['A'])
print(df)
# A B X
# 0 2017-11-01 12:24 2017年11月1日 12時24分 2017-11-01 12:24:00
# 1 2017-11-18 23:00 2017年11月18日 23時00分 2017-11-18 23:00:00
# 2 2017-12-05 5:05 2017年12月5日 5時05分 2017-12-05 05:05:00
# 3 2017-12-22 8:54 2017年12月22日 8時54分 2017-12-22 08:54:00
# 4 2018-01-08 14:20 2018年1月8日 14時20分 2018-01-08 14:20:00
# 5 2018-01-19 20:01 2018年1月19日 20時01分 2018-01-19 20:01:00
Timestamp型の属性・メソッド
pandas.to_datetime()
関数で変換した列のdtype
はdatetime64[ns]
型で、各要素はTimestamp
型となる。
print(df)
# A B X
# 0 2017-11-01 12:24 2017年11月1日 12時24分 2017-11-01 12:24:00
# 1 2017-11-18 23:00 2017年11月18日 23時00分 2017-11-18 23:00:00
# 2 2017-12-05 5:05 2017年12月5日 5時05分 2017-12-05 05:05:00
# 3 2017-12-22 8:54 2017年12月22日 8時54分 2017-12-22 08:54:00
# 4 2018-01-08 14:20 2018年1月8日 14時20分 2018-01-08 14:20:00
# 5 2018-01-19 20:01 2018年1月19日 20時01分 2018-01-19 20:01:00
print(df.dtypes)
# A object
# B object
# X datetime64[ns]
# dtype: object
print(df['X'][0])
# 2017-11-01 12:24:00
print(type(df['X'][0]))
# <class 'pandas._libs.tslib.Timestamp'>
Timestamp
型はPythonの標準ライブラリdatetime
のdatetime
型を継承し拡張した型。
print(issubclass(pd.Timestamp, datetime.datetime))
# True
年月日(year
, month
, day
)、時分秒(hour
, minute
, second
)、曜日(文字列: weekday_name
, 数値: dayofweek
)などを属性として取得できる。
print(df['X'][0].year)
# 2017
print(df['X'][0].weekday_name)
# Wednesday
また、to_pydatetime()
でPython標準ライブラリのdatetime
型、to_datetime64()
でNumPyのdatetime64[ns]
型に変換したりもできる。
py_dt = df['X'][0].to_pydatetime()
print(type(py_dt))
# <class 'datetime.datetime'>
dt64 = df['X'][0].to_datetime64()
print(type(dt64))
# <class 'numpy.datetime64'>
timestamp()
はUNIX時間(エポック秒 = 1970年1月1日0時0分0秒からの秒数)を浮動小数点float
型で返すメソッド。整数にしたいときはint()
を使う。
print(df['X'][0].timestamp())
# 1509539040.0
print(pd.to_datetime('1970-01-01 00:00:00').timestamp())
# 0.0
print(int(df['X'][0].timestamp()))
# 1509539040
Python標準ライブラリのdatetime
型と同様にstrftime()
で任意のフォーマットの文字列に変換することも可能。列の要素すべてに適用する方法は後述。
print(df['X'][0].strftime('%Y/%m/%d'))
# 2017/11/01
dtアクセサで列全体を一括処理
pandas.Series
全体に文字列処理を適用するstr
アクセサがある。
同様に、pandas.Series
全体に日時処理を適用するdt
アクセサがある。
年月日、曜日などを抽出
Timestamp
型と同様に、年月日(year
, month
, day
)、時分秒(hour
, minute
, second
)、曜日(文字列: weekday_name
, 数値: dayofweek
)などを属性として取得できる。
dt
のあとに各属性名を記述する。
pandas.Series
の各要素が処理され、pandas.Series
が返る。
print(df['X'].dt.year)
# 0 2017
# 1 2017
# 2 2017
# 3 2017
# 4 2018
# 5 2018
# Name: X, dtype: int64
print(df['X'].dt.hour)
# 0 12
# 1 23
# 2 5
# 3 8
# 4 14
# 5 20
# Name: X, dtype: int64
dayofweek
(月曜が0, 日曜が6)を利用して、特定の曜日の行のみを抽出したりすることも可能。
print(df['X'].dt.dayofweek)
# 0 2
# 1 5
# 2 1
# 3 4
# 4 0
# 5 4
# Name: X, dtype: int64
print(df[df['X'].dt.dayofweek == 4])
# A B X
# 3 2017-12-22 8:54 2017年12月22日 8時54分 2017-12-22 08:54:00
# 5 2018-01-19 20:01 2018年1月19日 20時01分 2018-01-19 20:01:00
任意のフォーマットで日時を文字列に変換
datetime64[ns]
型の列をastype()
メソッドで文字列str
型に変換すると、標準的な書式で文字列に変換される。
print(df['X'].astype(str))
# 0 2017-11-01 12:24:00
# 1 2017-11-18 23:00:00
# 2 2017-12-05 05:05:00
# 3 2017-12-22 08:54:00
# 4 2018-01-08 14:20:00
# 5 2018-01-19 20:01:00
# Name: X, dtype: object
dt.strftime()
で列を一括で任意のフォーマットの文字列に変換できる。日付のみや時刻のみの文字列にすることも可能。
print(df['X'].dt.strftime('%A, %B %d, %Y'))
# 0 Wednesday, November 01, 2017
# 1 Saturday, November 18, 2017
# 2 Tuesday, December 05, 2017
# 3 Friday, December 22, 2017
# 4 Monday, January 08, 2018
# 5 Friday, January 19, 2018
# Name: X, dtype: object
print(df['X'].dt.strftime('%Y年%m月%d日'))
# 0 2017年11月01日
# 1 2017年11月18日
# 2 2017年12月05日
# 3 2017年12月22日
# 4 2018年01月08日
# 5 2018年01月19日
# Name: X, dtype: object
文字列に変換した列をpandas.DataFrame
に新たな列として追加したい場合は、新たな列名を指定して代入すればよい。元の列名を指定すれば上書きされる。
df['en'] = df['X'].dt.strftime('%A, %B %d, %Y')
df['jp'] = df['X'].dt.strftime('%Y年%m月%d日')
print(df)
# A B X \
# 0 2017-11-01 12:24 2017年11月1日 12時24分 2017-11-01 12:24:00
# 1 2017-11-18 23:00 2017年11月18日 23時00分 2017-11-18 23:00:00
# 2 2017-12-05 5:05 2017年12月5日 5時05分 2017-12-05 05:05:00
# 3 2017-12-22 8:54 2017年12月22日 8時54分 2017-12-22 08:54:00
# 4 2018-01-08 14:20 2018年1月8日 14時20分 2018-01-08 14:20:00
# 5 2018-01-19 20:01 2018年1月19日 20時01分 2018-01-19 20:01:00
# en jp
# 0 Wednesday, November 01, 2017 2017年11月01日
# 1 Saturday, November 18, 2017 2017年11月18日
# 2 Tuesday, December 05, 2017 2017年12月05日
# 3 Friday, December 22, 2017 2017年12月22日
# 4 Monday, January 08, 2018 2018年01月08日
# 5 Friday, January 19, 2018 2018年01月19日
Pythonのdataframe型、NumPyのdatetime64[ns]型の配列に変換
dt.to_pydatetime()
でPython標準ライブラリのdatetime
型のオブジェクトを要素とするNumPy配列ndarrayを取得できる。
print(df['X'].dt.to_pydatetime())
# [datetime.datetime(2017, 11, 1, 12, 24)
# datetime.datetime(2017, 11, 18, 23, 0)
# datetime.datetime(2017, 12, 5, 5, 5)
# datetime.datetime(2017, 12, 22, 8, 54)
# datetime.datetime(2018, 1, 8, 14, 20)
# datetime.datetime(2018, 1, 19, 20, 1)]
print(type(df['X'].dt.to_pydatetime()))
print(type(df['X'].dt.to_pydatetime()[0]))
# <class 'numpy.ndarray'>
# <class 'datetime.datetime'>
NumPyのdatetime64[ns]
型の配列はメソッドではなくvalues
属性で取得できる。
print(df['X'].values)
# ['2017-11-01T12:24:00.000000000' '2017-11-18T23:00:00.000000000'
# '2017-12-05T05:05:00.000000000' '2017-12-22T08:54:00.000000000'
# '2018-01-08T14:20:00.000000000' '2018-01-19T20:01:00.000000000']
print(type(df['X'].values))
print(type(df['X'].values[0]))
# <class 'numpy.ndarray'>
# <class 'numpy.datetime64'>
dtに用意されていないメソッドの場合
例えば、UNIX時間(エポック秒)を返すメソッド(timestamp()
)はTimestamp
型にはあるが、dt
アクセサには用意されていない。そのような場合はmap()
を使えばOK。
print(df['X'].map(pd.Timestamp.timestamp))
# 0 1.509539e+09
# 1 1.511046e+09
# 2 1.512450e+09
# 3 1.513933e+09
# 4 1.515421e+09
# 5 1.516392e+09
# Name: X, dtype: float64
整数int
型に変換したい場合はastype()
メソッドを使う。
print(df['X'].map(pd.Timestamp.timestamp).astype(int))
# 0 1509539040
# 1 1511046000
# 2 1512450300
# 3 1513932840
# 4 1515421200
# 5 1516392060
# Name: X, dtype: int64
DatetimeIndexの場合
datetime64[ns]
型の列をインデックスに指定すると、そのインデックスはDatetimeIndex
型となる。
時系列データを処理する場合にはとても便利。詳細は以下の記事を参照。
例では、set_index()
で既存の列をインデックスに指定し、便宜上、余分な列をdrop()
メソッドで削除している。
df_i = df.set_index('X').drop(['en', 'jp'], axis=1)
print(df_i)
# A B
# X
# 2017-11-01 12:24:00 2017-11-01 12:24 2017年11月1日 12時24分
# 2017-11-18 23:00:00 2017-11-18 23:00 2017年11月18日 23時00分
# 2017-12-05 05:05:00 2017-12-05 5:05 2017年12月5日 5時05分
# 2017-12-22 08:54:00 2017-12-22 8:54 2017年12月22日 8時54分
# 2018-01-08 14:20:00 2018-01-08 14:20 2018年1月8日 14時20分
# 2018-01-19 20:01:00 2018-01-19 20:01 2018年1月19日 20時01分
print(df_i.index)
# DatetimeIndex(['2017-11-01 12:24:00', '2017-11-18 23:00:00',
# '2017-12-05 05:05:00', '2017-12-22 08:54:00',
# '2018-01-08 14:20:00', '2018-01-19 20:01:00'],
# dtype='datetime64[ns]', name='X', freq=None)
DatetimeIndex
型のインデックスには年月日(year
, month
, day
)、時分秒(hour
, minute
, second
)、曜日(文字列: weekday_name
, 数値: dayofweek
)などの属性や、strftime()
などのメソッドが用意されているため、dt
属性を介さずにインデックスの要素を一括で処理できる。
返る型はpandas.Series
でなく属性やメソッドによって異なるが、pandas.DataFrame
に新たな列として追加する場合は、新たな列名を指定して代入すればよい。
print(df_i.index.minute)
# Int64Index([24, 0, 5, 54, 20, 1], dtype='int64', name='X')
print(df_i.index.strftime('%y/%m/%d'))
# ['17/11/01' '17/11/18' '17/12/05' '17/12/22' '18/01/08' '18/01/19']
df_i['min'] = df_i.index.minute
df_i['str'] = df_i.index.strftime('%y/%m/%d')
print(df_i)
# A B min str
# X
# 2017-11-01 12:24:00 2017-11-01 12:24 2017年11月1日 12時24分 24 17/11/01
# 2017-11-18 23:00:00 2017-11-18 23:00 2017年11月18日 23時00分 0 17/11/18
# 2017-12-05 05:05:00 2017-12-05 5:05 2017年12月5日 5時05分 5 17/12/05
# 2017-12-22 08:54:00 2017-12-22 8:54 2017年12月22日 8時54分 54 17/12/22
# 2018-01-08 14:20:00 2018-01-08 14:20 2018年1月8日 14時20分 20 18/01/08
# 2018-01-19 20:01:00 2018-01-19 20:01 2018年1月19日 20時01分 1 18/01/19
ファイルからの読み込み時に文字列をdatetime64[ns]型に変換
データをファイルから読み込む場合は、読み込み時に文字列をdatetime64[ns]
型に変換できる。
pandas.read_csv()
関数の場合は引数parse_dates
にdatetime64[ns]
型に変換したい列番号をリストで指定する。一つだけの場合もリストにする必要があるので注意。
df_csv = pd.read_csv('data/src/sample_datetime_multi.csv', parse_dates=[0])
print(df_csv)
# A B
# 0 2017-11-01 12:24:00 2017年11月1日 12時24分
# 1 2017-11-18 23:00:00 2017年11月18日 23時00分
# 2 2017-12-05 05:05:00 2017年12月5日 5時05分
# 3 2017-12-22 08:54:00 2017年12月22日 8時54分
# 4 2018-01-08 14:20:00 2018年1月8日 14時20分
# 5 2018-01-19 20:01:00 2018年1月19日 20時01分
print(df_csv.dtypes)
# A datetime64[ns]
# B object
# dtype: object
標準的な書式ではない場合は引数date_parser
に変換する関数を指定する。ここでは無名関数(ラムダ式)で定義している。
df_csv_jp = pd.read_csv('data/src/sample_datetime_multi.csv',
parse_dates=[1],
date_parser=lambda date: pd.to_datetime(date, format='%Y年%m月%d日 %H時%M分'))
print(df_csv_jp)
# A B
# 0 2017-11-01 12:24 2017-11-01 12:24:00
# 1 2017-11-18 23:00 2017-11-18 23:00:00
# 2 2017-12-05 5:05 2017-12-05 05:05:00
# 3 2017-12-22 8:54 2017-12-22 08:54:00
# 4 2018-01-08 14:20 2018-01-08 14:20:00
# 5 2018-01-19 20:01 2018-01-19 20:01:00
print(df_csv_jp.dtypes)
# A object
# B datetime64[ns]
# dtype: object
引数index_col
でインデックスとする列を指定できる。
その場合、引数parse_dates=True
とするとインデックスの列がdatetime64[ns]
型に変換される。
df_csv_jp_i = pd.read_csv('data/src/sample_datetime_multi.csv',
index_col=1,
parse_dates=True,
date_parser=lambda date: pd.to_datetime(date, format='%Y年%m月%d日 %H時%M分'))
print(df_csv_jp_i)
# A
# B
# 2017-11-01 12:24:00 2017-11-01 12:24
# 2017-11-18 23:00:00 2017-11-18 23:00
# 2017-12-05 05:05:00 2017-12-05 5:05
# 2017-12-22 08:54:00 2017-12-22 8:54
# 2018-01-08 14:20:00 2018-01-08 14:20
# 2018-01-19 20:01:00 2018-01-19 20:01
print(df_csv_jp_i.index)
# DatetimeIndex(['2017-11-01 12:24:00', '2017-11-18 23:00:00',
# '2017-12-05 05:05:00', '2017-12-22 08:54:00',
# '2018-01-08 14:20:00', '2018-01-19 20:01:00'],
# dtype='datetime64[ns]', name='B', freq=None)
エクセルファイルを読み込むpandas.read_excel()
関数にも引数parse_dates
, date_parser
, index_col
があるので、同様に読み込み時に変換できる。pandas.read_excel()
関数については以下の記事を参照。