Pandasの日付データと文字列をそれぞれ変換する方法〜strアクセサとdtアクセサ

lecture

Pythonの日付、時間に関わるデータ型の基本については「Pythonで日付と時間を扱う方法」を参照ください。
ここでは主にPandasのSeriesやDataFrameで日付、時間データをstr型からdatetime型に変換する方法、そしてdatetime型から文字列に変換する方法を説明しています。
特に、Seriesになった日付データをフォーマットされた文字列に変換するにはstrアクセサやdtアクセサを使うと便利に変換できます。

スポンサーリンク

str型の日付データをdatetime型に変換

前処理で、日付データが「文字列」の場合には「datetime型」に変えたり、その逆で「datetime型」のものを「文字列」に変えたい場合があると思います。
まずはその方法から説明します。

次のサンプルは、Series型になった日付データを作成しています。(つまりDataFrameの日付列を抜き出した状態)
Seriesの含む要素の型はstr型です。
その要素の型をPandasのpd.to_datetime関数でdatetime型に変えています。

import pandas as pd

my_data = pd.Series(['2020-07-07','2020-08-07','2020-09-07','2020-10-07'])
data = pd.to_datetime(my_data)
data

結果
0 2020-07-07
1 2020-08-07
2 2020-09-07
3 2020-10-07
dtype: datetime64[ns]

pd.to_datetime関数について

pd.to_datetime関数は文字列データや数値データを日付データであるdatetime64型に変換してくれます。

詳細なPandasのpd.to_datetime関数については以下のドキュメントを参考にしてください。

pd.to_datetimeについて

pandas.to_datetimeドキュメント

  • pandas.to_datetime(arg : DatetimeScalar、errors : str = ‘…’、dayfirst : bool = ‘…’、yearfirst : bool = ‘…’、utc : オプション[ bool ] = ‘…’、format : オプション[ str ] = ‘…’、exact : bool = ‘…’、unit : オプション[ str] = ‘…’、 infer_datetime_format : bool = ‘…’、 origin = ‘…’、 cache : bool = ‘…’)→Union [DatetimeScalar、 ‘NaTType’]
  • pandas.to_datetime(arg : ‘Series’、errors: str = ‘…’、dayfirst : bool = ‘…’、yearfirst : bool = ‘…’、utc : オプション[ bool ] = ‘…’、形式: オプション[ str ] = ‘…’、exact : bool = ‘…’、単位: オプション[ str ] = ‘…’、 infer_datetime_format : bool = ‘…’、 origin = ‘…’、 cache : bool = ‘…’) → ‘Series’
  • pandas.to_datetime(arg : Union [ List 、 Tuple ]、errors : str = ‘…’、dayfirst : bool = ‘…’、yearfirst : bool = ‘…’、utc : オプション[ bool ] = ‘.. 。 ‘、format : オプション[ str ] = ‘ … ‘、exact : bool = ‘ … ‘、unit: オプション[ str ] = ‘…’、 infer_datetime_format : bool = ‘…’、 origin = ‘…’、 cache : bool = ‘…’) →DatetimeIndex

パラメーター

  • arg: int、float、str、datetime、list、tuple、1次元配列、Series、DataFrame / dict-like
    日時に変換するオブジェクト。
  • errors:{‘ignore’、 ‘raise’、 ‘coerce’}、デフォルトは ‘raise’
    • ‘raise’の場合、無効な解析により例外が発生
    • ‘coerce’の場合、無効な解析はNaTとして設定
    • ‘ignore’の場合、無効な解析は入力を返す
  • dayfirst bool、デフォルトはFalse
    argがstrまたはそのリストに似ている場合は、日付の解析順序を指定します。Trueの場合、日付を最初に解析します。たとえば、10/11/12は2012-11-10として解析されます。警告:dayfirst = Trueは厳密ではありませんが、最初に解析することを優先します(これは、dateutilの動作に基づく既知のバグです)。
  • yearfirst bool、デフォルトはFalse
    argがstrまたはそのリストに似ている場合は、日付の解析順序を指定します。

    Trueが最初に年で日付を解析する場合、たとえば10/11/12は2010-11-12として解析されます。

    dayfirstとyearfirstの両方がTrueの場合、yearfirstが優先されます(dateutilと同じ)。
    警告:yearfirst = Trueは厳密ではありませんが、最初に年で解析することを好みます(これはdateutilの動作に基づく既知のバグです)。

  • utc bool、デフォルトはなし
    Trueの場合、UTC DatetimeIndexを返します(tz対応のdatetime.datetimeオブジェクトも変換します)。
  • format:str、デフォルトなし
    「%d /%m /%Y」など、時間を解析するstrftimeは、「%f」がナノ秒まで解析することに注意してください。選択肢の詳細については、https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behaviorのstrftimeドキュメントを参照して ください。
  • exact:ブール、デフォルトではTrue
    次のように動作します。-Trueの場合、完全に一致するフォーマットが必要です。-Falseの場合、ターゲット文字列のどこにでも一致するフォーマットを許可します。
  • unit:str、デフォルトは「ns」
    引数の単位(D、s、ms、us、ns)は、整数または浮動小数点数である単位を示します。これは原点に基づいて行われます。例:unit = ‘ms’およびorigin = ‘unix’(デフォルト)の場合、これはUNIXエポックスタートまでのミリ秒数を計算します。
  • infer_datetime_format: bool、デフォルトはFalse
    Trueで形式が指定されていない場合は、最初の非NaN要素に基づいて日時文字列の形式を推測し、推測できる場合は、より高速な解析方法に切り替えます。場合によっては、これにより解析速度が5〜10倍向上することがあります。
  • origin:scalar,デフォルトは ‘unix’
    参照日を定義します。数値は、この参照日以降のユニット数(unitで定義)として解析されます。

    • ‘unix’(またはPOSIX)時間の場合。originは1970-01-01に設定されています。
    • 「ジュリアン」の場合、単位は「D」でなければならず、起源はユリウス暦の最初に設定されます。ユリウス日番号0は、紀元前4713年1月1日正午から始まる日に割り当てられます。
    • タイムスタンプ変換可能な場合、originはoriginで識別されるタイムスタンプに設定されます。
  • cache:ブール、デフォルトはTrue
    Trueの場合、一意の変換された日付のキャッシュを使用して、日時変換を適用します。重複する日付文字列、特にタイムゾーンオフセットのある文字列を解析するときに、大幅なスピードアップが得られる場合があります。キャッシュは、少なくとも50個の値がある場合にのみ使用されます。範囲外の値が存在すると、キャッシュが使用できなくなり、解析が遅くなる可能性があります。
    バージョン0.23.0の新機能。
    バージョン0.25.0で変更: -デフォルト値をFalseからTrueに変更しました。

戻り値:日付時刻

解析が成功した場合。戻り値の型は入力に依存します

  • list-like::DatetimeIndex
  • Series::datetime64 dtypeのシリーズ
  • scalar:タイムスタンプ

指定されたタイプを返すことができない場合(たとえば、入力の要素がTimestamp.minより前またはTimestamp.maxより後の場合)、戻り値はdatetime.datetimeタイプ(または対応する配列/シリーズ)になります。

pd.to_datetime関数の引数にformat を指定すると好きなフォーマットで表示できます。
フォーマットの指定は次の表のとおりです。

説明
%Y 4桁の年数 (例 2018,1996…)
%y 2桁の年数 (例 18, 96..)
%m 2桁の月 [01,12] (例 01, 07, 12..)
%d 2桁の日付 [01,31] (例 02, 28, 31..)
%H 24時間表記の時間 [00,23] (例 00, 12, 21..)
%I 12時間表記の時間 [01,12] (例 01, 07, 12..)
%M 2桁の分 [00, 59] (例 00, 05, 38, 59..)
%S 秒 [00, 61] (例 00, 15, 39, 60, 61..)
60,61は00,01と同じ
%w 整数表記された曜日 [0(日曜), 6] (例 1(月曜), 4(木曜), 6(土曜)…)
%U 週番号 [00,53] 日曜が週の始めとしてカウントされる。年を通しての週の番号 (例 00, 03, 04, 52..)
%W 週番号 [00,53] 月曜が週の始めとしてカウントされる、年を通しての週の番号
%z UTC タイムゾーンからのオフセット +HHMMまたは-HHMMの形
(例 +0800, -0925,…)

日付型データを様々なフォーマットの文字列型に変換

今度は、datetime型の日付データをstr型に変更し、さらに日付フォーマットを行います。
datetime型は特にフォーマットは気にしなくても、決まりのフォーマットを使いコンピュータに日付と認識させることが重要でした。
一方str型の場合は人間がわかりやすいフォーマットに変更することが重要です。
さて、そこで問題が起こるのは、Series型の日付データを一括でフォーマットする方法について説明します。

まず前提として、str型の日付データがSeriesの状態であるとします。
このとき、日付のフォーマットを変更したい場合、replace関数で次のような処理をしてもうまくいきません。
このようにすると、replace関数はSeriesの中に”-“という要素があるかどうか探します。
そのため結果は全ての要素がマッチせずに何も変化が起こりません。

次のコードがその例です。

import pandas as pd

my_data = pd.Series(['2020-07-07', '2020-08-07', '2020-09-07', '2020-10-07'])
data = my_data.replace("-", "")
data

結果
0 2020-07-07
1 2020-08-07
2 2020-09-07
3 2020-10-07
dtype: object

それでは、ひとつひとつの要素に”-“が含まれているかどうかを調べるにはどうしたら良いのでしょうか。
この場合は、map関数やlambda関数を使って処理する必要があります。

次の例は、map関数を使ったコードです。

import pandas as pd

my_data = pd.Series(['2020-07-07', '2020-08-07', '2020-09-07', '2020-10-07'])
data = my_data.map(lambda x : x.replace("-", ""))
data

結果
0 20200707
1 20200807
2 20200907
3 20201007
dtype: object

しかし、map関数を使うと困ることがあります。
それは欠損値がある場合にエラーになってしまうことです。

次の例が欠損値がある場合にmap関数で処理したコードです。(エラーになります)

import pandas as pd
import numpy as np

my_data = pd.Series(['2020-07-07', np.nan, '2020-09-07', '2020-10-07'])
data = my_data.map(lambda x : x.replace("-", ""))
data

結果
—————————————————————————
AttributeError Traceback (most recent call last)
in ()
3
4 my_data = pd.Series([‘2020-07-07′,np.nan,’2020-09-07′,’2020-10-07’])
—-> 5 data = my_data.map(lambda x : x.replace(“-“, “”))
6 data

2 frames
pandas/_libs/lib.pyx in pandas._libs.lib.map_infer()

in (x)
3
4 my_data = pd.Series([‘2020-07-07′,np.nan,’2020-09-07′,’2020-10-07’])
—-> 5 data = my_data.map(lambda x : x.replace(“-“, “”))
6 data

AttributeError: ‘float’ object has no attribute ‘replace’

strアクセサとdtアクセサ

Pandasでは、pandas.DataFrameの列や行(= pandas.Series)の要素の文字列に対して一括で処理を行うために、pandas.Seriesに文字列メソッドが準備されています。
これらのメソッドを使うことで、Seriesの要素に対して処理を行うことができます。
これらには、strアクセサを使っていることが特徴です。
さらにこれらのメソッドは、欠損値を無視してくれます。

置換 str.replace()
空白削除 str.strip()
str.lstrip()
str.rstrip()
大文字小文字変換 str.lower()
str.upper()
str.capitalize()
str.title()

strアクセサを介して文字列メソッドを使用した例。

import pandas as pd
import numpy as np

my_data = pd.Series(['2020-07-07', np.nan, '2020-09-07', '2020-10-07'])
data = my_data.str.replace("-", "")
data

結果
0 20200707
1 20200807
2 20200907
3 20201007
dtype: object

datetime型の要素を持つSeriesデータをフォーマットしたstr型の要素に変換

次の例は、datetime型の日付データがSeriesになっているとして、それをobject型にしつつ尚且つ特定のフォーマットにしたものです。
Seriesのdtypeはobject型ですが、それぞれの要素はstr型になっています。
datetime型の日付データに対してdtアクセサを介してstrftime()でフォーマットを変更します。

import pandas as pd

my_data = pd.Series(['2020-07-07','2020-08-07','2020-09-07','2020-10-07'])
data = pd.to_datetime(my_data) 
data.dt.strftime('%Y%m')

結果
0 20200707
1 NaN
2 20200907
3 20201007
dtype: object

strアクセサとdtアクセサは隠れた名選手です。上手に使ってシンプルなコードが書けますので是非覚えておきましょう。

タイトルとURLをコピーしました