はじめに
PandasのDFでデータを扱うとき。最初はあまり意識しないが、すぐにデータ型という概念にぶつかる。
というのも、例えばread_csv等でデータを読み込む際、pandas側でいいように型を設定してくれるのだが、
ふとした拍子で意外な型になっており、そのデータを扱う際にエラーになったりすることがある。
なのでデータ型の変更や、データ型毎の代表的な処理をまとめてみた。
存在するデータ型
pandasのdocにきれいにまとまっていればいいのだけれど、見当たらず。
以下以外にもあるようだが、主要どころを理解するという意味では以下を理解すればよさそう。
用途 | Pandas | Python |
---|---|---|
文字列 複数データ混合 |
object | (内容による) |
整数 | int64 | int |
浮動小数 | float64 | float |
真/偽 | bool | bool |
日付、時刻 | datetime64 | - |
2つの時刻の差 | timedelta[ns] | - |
カテゴリ | category | - |
上記以外にも、pandasの型として以下のようなものもある。
必要な時が来たら追加で整理したい。
- int8、int16、int32:それぞれ末尾の数字=ビット数 ※int以外にも同様の概念あり
- unit64:int64と同様に整数だが、unit64の場合符号なし。
- complex128:複素数。実部と虚部がそれぞれfloat64で、全体として128
- category:カテゴリデータ。性別を0や1で示すような、「数値+NaN」で扱うが、足し算引き算等をする意味のない値。int64と明確に区別するとき定義する
- string:文字列。厄介なことに昔のpandasにはなく、Ver1.0から導入されたらしい。
後方互換のためread時にはobject形で読み込まれるため、string型を意識的に使う人が少ない。
pandasのString型については以下記載あり。
objectでなく最初からStringで実装していればよかったなという雰囲気を感じる、、
実験用データの定義
import pandas as pd
import numpy as np
df = pd.DataFrame({"index":[0, 1, 2, 3],
"id":[1, 2, 3, 4],
"F-Name":['aa', 'bb', 'cc', 'dd'],
"L-Name":['AA', 'BB', 'CC', 'DD'],
"point1":[63, 37, 20, 90],
"point2":[31, 41, 66, np.nan],
"height":[165.3, 143.2, 174.2, 158.0],
"weight":[51, 47, 65, 56],
"sex":[1, 0, 1, 9],
"birth":['1992-12-01', '1995-03-20', '1986-10-09', '1998-07-14'],
"add_date":['2018年5月3日', '2019年10月18日', '2020年1月17日', '2021年9月13日'],
"upd_date":[20210103, 20210304, 20220404, 20211225],
"active":[True, False, True, True]}).set_index("index")
# id F-Name L-Name point1 point2 height weight sex birth add_date upd_date active
# index
# 0 1 aa AA 63 31.0 165.3 51 1 1992-12-01 2018年5月3日 20210103 True
# 1 2 bb BB 37 41.0 143.2 47 0 1995-03-20 2019年10月18日 20210304 False
# 2 3 cc CC 20 66.0 174.2 65 1 1986-10-09 2020年1月17日 20220404 True
# 3 4 dd DD 90 NaN 158.0 56 9 1998-07-14 2021年9月13日 20211225 True
データ型の表示:dtypes
df.dtypes
# id int64
# F-Name object
# L-Name object
# point1 int64
# point2 float64
# height float64
# sex int64
# birth object
# add_date object
# upd_date int64
# active bool
# dtype: object
- 整数はint64、文字列はobject、小数はfloat64、真偽はboolとなる
- NaNはpythonではfloatのみ、intでは存在しない概念のため、整数の中にNaNが含まれるとその列はfloat64になる
- 日付型も最初はobject(文字列)
- 意図する型と必ずしも一致しないケースがあり得る(例:weightはたまたま整数しかなかったからint64となっているが、本来小数も許容してほしい)
- 上記ではないが、一見数字でも、文字列として元データが定義していると、objectとして取り込まれることがある
データ型の変換:astype
# pandasの型名称で指定する場合は''で囲う
# pythonの型名称で指定する場合は''が不要
df = df.astype({'point1': float, 'weight': 'float64', 'sex': 'category'})
df.dtypes
# id int64
# F-Name object
# L-Name object
# point1 float64
# point2 float64
# height float64
# weight float64
# sex category
# birth object
# add_date object
# upd_date int64
# active bool
# dtype: object
データ型の変換(日付):to_datetime
df['birth'] = pd.to_datetime(df['birth'])
-
to_datetimeで変換できる日付文字列は以下
- 日付
表記法 例 区切りなし(※) 20230228 ハイフン 2023-02-28 スラッシュ 2023/02/28 MM-DD-YYYY 02-28-2023 区切りなしは扱いに注意。単に8文字の数字が並んだ文字列をto_datetimeにかけると、ミリ秒として処理される
結果、「1970-01-01 00:00:00.020210103」みたいな表記となってしまう。
これを回避する場合以下表記が必要Python# to_datetimeは文字列に対する処理のため、int64をobjectに変換 df = df.astype({'upd_date': 'object'}) # ミリ秒として扱われないように、formatで形式を指定 df['upd_date'] = pd.to_datetime(df['upd_date'], format='%Y%m%d')
-
to_datetimeで変換できる日付時刻文字列は以下
- 日付+時刻
日付部は上記の表の形式であればどれでも可
以下は区切りなしケースで例を記載
MM、SS部分を記載しない場合、00で補完される
表記法 例 日付T時刻 20230228T14:21:31 日付(スペース)時刻 20230228 14:21:31 AM、PM付き 20230228 02:21:31 PM
20230228T02:21:31 PM
20230228 02:21:31 AM
20230228T02:21:31 PM時刻区切りなし 20230228T142131 - 日付+時刻
to_datetimeで変換できない形式の文字列は、formatを用いて変換を行う
df["add_date"] = pd.to_datetime(df["add_date"], format="%Y年%m月%d日")
formatで指定できるコードは以下の通り
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
よく使うものを抜粋
フォーマットコード | 指定内容 | 例 |
---|---|---|
%Y | 4桁の年 | 2023 |
%m | 2桁の月 | 02 |
%d | 2桁の日 | 28 |
%H | 時間(24時間) | 13 |
%M | 分 | 26 |
%S | 秒 | 49 |
%y | 2桁の年 | 23 |
%B | 英語月 | February |
%b | 英語月(短縮) | Feb |
%X | HH:MM:SS | 13:26:49 |