データフレーム全体のデータ型をastypeで一括変換したかった
が、全然されない。なんでや!!となったのでメモ。
状況
数値データを前処理して、ある特定の列に含まれる文字を置換 → 型を object から int (あるいは float) に変更したい
その後列同士を引き算して特徴量を作りたかったが TypeError
、文字列は置換して数値データにしたハズなのになんで??? めっちゃ詰まった。
# d 列だけ型が違う print(df.dtypes) # a int64 # b int64 # c int64 # d object # 前処理して変換(したつもり) df = df.replace({'7..4': 74, '10未満': 10}).astype('int64') # 新しい特徴量を作成したかった df['d-a'] = df['d'] - df['a'] # TypeError: Cannot compare types 'ndarray(dtype=int64)' and 'str'
原因
replace
メソッドではデータフレーム全体に対して特定の要素を複数置換させることができるが、astype
メソッドは、全ての列の型が一致していること が必要。特定の列だけ型が違っていた場合、全体変換することができない。
(例)
OK な例
print(df.dtypes) # a int64 # b int64 # c int64 # d int64 df_f = df.astype('float64') print(df_f.dtypes) # a float64 # b float64 # c float64 # d float64
NG な例
print(df.dtypes) # a int64 # b int64 # c int64 # d object df_f = df.astype('float64') print(df_f.dtypes) # a int64 # b int64 # c int64 # d object
解決策
前処理で値を変換した後、
- データフレーム全体で変換する場合列を指定する
- 列個別に
astype
で変換する (元のデータフレームを変更)
# 1 df_icol = df.astype({'d': 'int64'}) # 2 df['d'] = df['d'].astype('int64')
結論:データフレーム全体を操作するときは注意
普通、データフレームに対する処理は列ごとにする。なぜなら特徴量が列ごとにあることが多いから。
今回なんでデータフレーム全体を処理したいかと言うと、ワイドフォーマット形式のパネルデータを扱っていたから。
- パネルデータとは:複数の個体が複数時点に渡って観測されているデータ。(例) 2013-2015年の大学の学部別志願者数・受験者数
- 時系列データとは:一つの個体が複数時点に渡って観察されているデータ。(例) 株価
- ワイドフォーマットは、時点がカラム、行が1サンプルになっている横並びデータのこと。
具体的に自分が扱っていたデータは、下図のように、一定期間ごとに観測された患者の検査値データがあって、検査の種類ごとにデータが分かれていた。
データの型は1つのデータフレームの中で統一のものだったので、一気に型変換や値の抽出を行いたかったのだ。
上で遭遇したエラー以外にも、例えばデータフレーム全体に条件式を適用させようとしても、想定通りにならないことがある。
(例) BMI 値が外れ値となっている患者(行)を抽出したい。
通常、列に条件式を適用させれば抽出することができる。
# '2008-10' に BMI 値が45以上の人を抽出 df[df['2008-10'] > 45]
# データ全体に条件式を適用させようとする df[df > 45]
ただこのサイト では、要素で抽出できる例があった。
どうなんだろう、、、 結局自分は、カラムごとに for 文を回して、条件に合うインデックスを検索して抽出する方法を取った。
内容が間違っていたら、指摘いただけると嬉しいです。