timestamp から 日付 or 時刻の文字列を取り出したい
CSV などから Pandas DataFrame (以下「DF」)に読み込んだ文字列(str)は、そのままだと何かと扱いにくいので、DF 上で timestamp 型にすると便利です。
しかし、資料などにするときは日付だけ、あるいは時刻だけを取り出したいこともあります。そこで、日付/時刻を一発取り出しする方法の一案です。
方法
作業の大まかな流れは次のとおりです。
上記以外の Scripts は、何も考えずに Loop で処理してしまった場合の失敗例ですから、読み飛ばしてしまって一向に差し支えありません😅
Data 読み込み
CSVなどから元データ(テキストデータ)を Pandas DataFreme (以下、「DF」)に読み込みます。
import pandas as pd df = pd.DataFrame( {'DATE_AND_TIME': ['2020-01-01 06:50', '2020-01-01 10:50', '2020-01-01 16:38', '2020-01-01 22:16'], 'EVENT': ['Sunrise in Tokyo', 'Moonrise in Tokyo', 'Sunset in Tokyo', 'Moonset in Tokyo'] } ) # This DF is spared for later use...🤫 df2 = df.copy() # Confirm df.head()
Fig. 1: 読み込んだデータ (df.head())
Fig. 2: 日付情報はそのままだと単なるテキスト (df.DATE_AND_TIME)
pandas.to_datetime() 登場!
そこで、秘技「pandas.to_datatime()」を使って data type を datetime に変換します。
cf. Pandas: CSVに文字型で記録されている日付と時間をPandasに読み込んだ後、日付・時刻型に一発変換したい
Script 2: みんなの味方 pandas.to_datetime()
# Convert object(str) to datetime df.DATE_AND_TIME = pd.to_datetime(df.DATE_AND_TIME) # Confirm df.DATE_AND_TIME
Fig. 3: ちゃんと datetime 型になっている (df.DATE_AND_TIME)
時刻データだけを抽出したい
この表のデータは全部 2020 年の元日のものなので、表中で同じ日付を繰り返すのは冗長になるからいらないかも、ということで、時刻データだけを取り出すことにします。
元の str オブジェクトのままだったら slice で取り出したり、場合によっては regex で切り出したりといろいろ面倒臭い話になるところでしたが、たったいま datetime 型に変換したので、日付だろうが時刻だろうが自由自在に取り出せます。
ということで、.strftime()
を使って時刻データを取り出すことにします(取り出し後は str オブジェクトになります)。
strftime で時刻文字列(str)に変換するぞ!
Script 3: strptime で時刻文字列のみに変換 (するつもり…)
# strftime を使うためにはこれ👇が必要です。 from datetime import datetime df.DATE_AND_TIME.strftime('%H:%M:%S')
Loop で簡単に解決!
Series' object has no attribute 'strftime'
(Series に strftime アトリビュートは無いよ)とかどうとか言ってるようです。Excel みたいに列を一発変換とかできないの?不便だな…。SEARCH STACK OVERFLOW
リンクを辿るのも面倒だからここはササッと loop で回しちゃった方が早いだろう。- ほら、簡単にできちゃた!天才だな👺。
# 'f'ormat datetime to str. for i in range(len(df)): df.at[i, 'DATE_AND_TIME'] = df.at[i, 'DATE_AND_TIME'].strftime('%H:%M:%S') # Confirm df # できた、できた!
あんなぁ…
などと蘊蓄を垂れていたら いずこからともなく神様の声が…
あんなぁ、Colab はんが親切に
SEARCH STACK OVERFLOW
のリンクを貼ってくださってるんやから素直に読んだらええやんか?これって、
pd.to_datetime
のあとdt
アクセサを使えば 1行で済む話違うんかい? Pandas の三種の神器 dt, str, cat も知らずに loop とか抜かしてる場合やないで、ホンマ💢
えらいすんまへん 🙇♂️
pandas.Series.dt.time で行こう!
ということで、仕切り直し。DF はやり直し用に用意しておいた df2 を使います。
Script 5: みんなの味方 pandas.to_datetime()、再登場
# Startng over. # Convert object(str) to datetime df2.DATE_AND_TIME = pd.to_datetime(df2.DATE_AND_TIME) # Confirm df2.DATE_AND_TIME
で、dt
(たぶん datetime の略)アクセサを使えば 1 行でおしまい 😸
df2.DATE_AND_TIME = df2.DATE_AND_TIME.dt.time # Confirm df2.DATE_AND_TIME # Note that the dtype is 'object' (str).
なお、日付文字列を取り出したい時は、df2.DATE_AND_TIME.dt.date
とすれば、OKです。
ただし、改めて Script 1 と Script 5 を先に走らせてください(Script 6 を走らせた後だと、df2.DATE_AND_TIME
は既に str
になっているので、Error
になってしまいます)。
Fig. 7: 時刻文字列(object/str)になっている
折角なので、列名(column name)を rename しておきます。
# Rename the column DATE_AND_TIME to TIME df2.rename(columns={'DATE_AND_TIME': 'TIME'}, inplace=True) # Confirm df2
Fig. 8: 完成!
ところが思わぬ伏兵が!
元データがお行儀よく作られているときはこれで良いのですが、ときおり TIME
column の cell が空欄だったり、日付や時刻と解釈することができないデータ(「不明」などついつい入れがちな文字列とか)だったりすると、AttributeError: Can only use .dt accessor with datetimelike values
を食らいます。つまり「dt
アクセサが相手にするのは日付時刻っぽいものだけなの!」という。
今回のような場合に限らず、series
(カラム)を弄るときにぶち当たりがちな壁です。そのような場合には apply()
先生に助けを請いましょう。
df2.DATE_AND_TIME = df2.DATE_AND_TIME.apply(pd.to_datetime) # これだけで解決!
Enjoy!
おまけ
上記の script に説明を加えた Jupyter Notebook を pandas_dt.ipynb_.zip [4 KB] (Preview)に置いておきました。Colab に upload すればそのまま使えます。