データを分析するときは、正しいデータ型でデータを扱わないと、予期しない結果やエラーが出る可能性があります。
Pythonでデータ分析をするときはPandasをよく使いますが、Pandasでは読み込んだデータの型を自動で推定してくれます。このときの精度は高く、初期の時点でおかしなデータ型として読み込まれることはあまりないと思います。
ですが、分析プロセスの途中でデータ型の変換が必要になるというケースは稀ではありません。
今回は、Pandasでの基本的なデータ型とデータ型の変換方法を具体的なデータを使いながら見ていこうと思います。
Pandasにおけるデータ型
データ型はプログラミング言語がそのデータをどのように格納、操作するかを識別するための内部構造です。
例えば、1+1の結果は2を返しますが、”こんにちは”+”みなさん”の結果は”こんにちはみなさん”となります。このような処理の違いを識別するために用いるのがデータ型です。
Pandasでは以下のようなデータ型の種類があります。
Pandasの型 | Pythonの型 | 用途 |
---|---|---|
object | str or mixed | 文字列や文字列と数値の混合型 |
int64 | int | 整数 |
float64 | float | 浮動小数点 |
bool | bool | 真/偽 |
datetime64 | NA | 日付および時刻 |
timedelta[ns] | NA | 2つの日時の差 |
category | NA | 文字列のカテゴリ |
PandasにおけるObject型は文字列型を指しますが、同時に複数のデータ型を含めることもできます。
ただし、1つの列に複数のデータ型の値を保持していると分析で困ることになります(後述します)。
使用するデータ
今回使用するデータは、以下リンクから取得したCSVファイルを使用します。
https://github.com/chris1610/pbpython/tree/master/data
import pandas as pd
df = pd.read_csv("input/sales_data_types.csv")
Customer Number | Customer Name | 2016 | 2017 | Percent Growth | Jan Units | Month | Day | Year | Active | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 10002 | Quest Industries | $125,000.00 | $162,500.00 | 30.00% | 500 | 1 | 10 | 2015 | Y |
1 | 552278 | Smith Plumbing | $920,000.00 | $1,012,000.00 | 10.00% | 700 | 6 | 15 | 2014 | Y |
2 | 23477 | ACME Industrial | $50,000.00 | $62,500.00 | 25.00% | 125 | 3 | 29 | 2016 | Y |
3 | 24900 | Brekke LTD | $350,000.00 | $490,000.00 | 4.00% | 75 | 10 | 27 | 2015 | Y |
4 | 651029 | Harbor Co | $15,000.00 | $12,750.00 | -15.00% | Closed | 2 | 2 | 2014 | N |
値は全て埋まっており、分析には使えそうなデータです。
Pandasでの処理
データ型を確認する
データを読み込んだところで、データフレームのデータ型を確認します。
データ型を確認するには、df.dtypesを使います。
df.dtypes
さて、各データ型はそれぞれふさわしいデータ型になっているのでしょうか?
- “Customer Number”はint型の方がよさそう
- “2016”および”2017″は数値型として扱いたい
- “Percent Growth”と”Jan Units”も数値として扱いたい
- “Month”, “Day”, “Year”は日付型で扱いたい
- “Active”はYesかNoのbool型としたい
こんな感じで、分析するためのデータ型とはなっていないようです。なので、それぞれ目的のデータ型に変換する必要があります。
データ型を変換する(文字列→数値)
Pandasでデータ型を変換するにはdf.astype()を用います。
例として、”Customer Number”をint型に変換します。
df['Customer Number'] = df['Customer Number'].astype('int')
print(df.dtypes)
データ型が変換されていることがわかります。
目的の型に変換できないとき
同様にして、他の列も目的の型に変換していきます。次は”2016″を数値型に変換してみます。
df['2016'] = df['2016'].astype('float')
といきたいところですが、エラーが出てしまいました。
どうやら「$」や「,」が原因みたいです。数値として扱うにはこれらを取り除く必要がありそうです。
文字列の置換にはreplace()を使います。また、簡潔に表現するためにlambda関数を使用します。
lambda x: x.replace('$', '').replace(',', '')
また、”2016″の列全ての項目に上記のlanbda関数を適用する必要があります。df.apply()を使うと、各項目に引数に渡した関数の処理を実行することができます。
そして、最後にfloat型に変換します。
df['2016'] = df['2016'].apply(lambda x: x.replace('$', '').replace(',', '')).astype('float')
変換することができました。ちなみに”2016″の値はどうなっているのかというと、以下のようになっています。
Customer Number | Customer Name | 2016 | 2017 | Percent Growth | Jan Units | Month | Day | Year | Active | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 10002 | Quest Industries | 125000 | $162,500.00 | 30.00% | 500 | 1 | 10 | 2015 | Y |
1 | 552278 | Smith Plumbing | 920000 | $1,012,000.00 | 10.00% | 700 | 6 | 15 | 2014 | Y |
2 | 23477 | ACME Industrial | 50000 | $62,500.00 | 25.00% | 125 | 3 | 29 | 2016 | Y |
3 | 24900 | Brekke LTD | 350000 | $490,000.00 | 4.00% | 75 | 10 | 27 | 2015 | Y |
4 | 651029 | Harbor Co | 15000 | $12,750.00 | -15.00% | Closed | 2 | 2 | 2014 | N |
きれいな数値になっていることがわかります。
同様に”2017″、”Percent Growth”も数値に変換していきます。 “Percent Growth” は元の百分率より小数の値の方が扱いやすいので100で割っておきます。
df['2017'] = df['2017'].apply(lambda x: x.replace('$', '').replace(',', '')).astype('float')
df['Percent Growth'] = df['Percent Growth'].apply(lambda x: x.replace('%', '')).astype('float') / 100
“Jan Units”も同様に数値に変換していこうとすると、エラーが発生してしまいます。最後の項目が「Closed」となっており、数値変換できないためです。
こういったケースではdf.astype()ではなくpd.to_numeric()を用いることで、より柔軟に対応することができます。引数にerrors=”coerce”を追加することで、変換できない項目は欠損に変換することができます。
df['Jan Units'] = pd.to_numeric(df['Jan Units'], errors='coerce')
Customer Number | Customer Name | 2016 | 2017 | Percent Growth | Jan Units | Month | Day | Year | Active | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 10002 | Quest Industries | 125000 | 162500 | 0.3 | 500 | 1 | 10 | 2015 | Y |
1 | 552278 | Smith Plumbing | 920000 | 1012000 | 0.11 | 700 | 6 | 15 | 2014 | Y |
2 | 23477 | ACME Industrial | 50000 | 62500 | 0.25 | 125 | 3 | 29 | 2016 | Y |
3 | 24900 | Brekke LTD | 350000 | 490000 | 0.04 | 75 | 10 | 27 | 2015 | Y |
4 | 651029 | Harbor Co | 15000 | 12750 | -0.15 | nan | 2 | 2 | 2014 | N |
欠損値も分析においては好ましくないので、何等か処置をする必要があります。今回は欠損を0で置き換える処理を追加します。
df["Jan Units"] = pd.to_numeric(df['Jan Units'], errors='coerce').fillna(0)
Customer Number | Customer Name | 2016 | 2017 | Percent Growth | Jan Units | Month | Day | Year | Active | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 10002 | Quest Industries | 125000 | 162500 | 0.3 | 500 | 1 | 10 | 2015 | Y |
1 | 552278 | Smith Plumbing | 920000 | 1012000 | 0.11 | 700 | 6 | 15 | 2014 | Y |
2 | 23477 | ACME Industrial | 50000 | 62500 | 0.25 | 125 | 3 | 29 | 2016 | Y |
3 | 24900 | Brekke LTD | 350000 | 490000 | 0.04 | 75 | 10 | 27 | 2015 | Y |
4 | 651029 | Harbor Co | 15000 | 12750 | -0.15 | 0 | 2 | 2 | 2014 | N |
データ型を変換する(文字列→日付)
次は”Month”、”Day”、”Year”を日付型に変換します。
日付型に変換するためには、年月日をまとめる必要があります。なので、元のデータフレームの列を日付型にするのではなく、新規に”Time”列を作成します。
日付型への変換は pd.to_datetime ()を用います。
df["Time"] = pd.to_datetime(df[['Month', 'Day', 'Year']])
Customer Number | Customer Name | 2016 | 2017 | Percent Growth | Jan Units | Month | Day | Year | Active | Time | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10002 | Quest Industries | 125000 | 162500 | 0.3 | 500 | 1 | 10 | 2015 | Y | 2015/1/10 |
1 | 552278 | Smith Plumbing | 920000 | 1012000 | 0.1 | 700 | 6 | 15 | 2014 | Y | 2014/6/15 |
2 | 23477 | ACME Industrial | 50000 | 62500 | 0.25 | 125 | 3 | 29 | 2016 | Y | 2016/3/29 |
3 | 24900 | Brekke LTD | 350000 | 490000 | 0.04 | 75 | 10 | 27 | 2015 | Y | 2015/10/27 |
4 | 651029 | Harbor Co | 15000 | 12750 | -0.15 | 0 | 2 | 2 | 2014 | N | 2014/2/2 |
“Time”列はdatetime型です。
データ型を変換する(文字列→bool型)
次は”Active”をbool型に変換します。変換するにあたり、numpy(np)を使用します。np.where()でどの条件を真(偽)とするかというルールを指定し、変換します。
以下では、”Y”をTrue、それ以外をFalseとします。
import numpy as np
df["Active"] = np.where(df["Active"] == "Y", True, False)
Customer Number | Customer Name | 2016 | 2017 | Percent Growth | Jan Units | Month | Day | Year | Active | Time | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10002 | Quest Industries | 125000 | 162500 | 0.3 | 500 | 1 | 10 | 2015 | TRUE | 2015/1/10 |
1 | 552278 | Smith Plumbing | 920000 | 1012000 | 0.1 | 700 | 6 | 15 | 2014 | TRUE | 2014/6/15 |
2 | 23477 | ACME Industrial | 50000 | 62500 | 0.25 | 125 | 3 | 29 | 2016 | TRUE | 2016/3/29 |
3 | 24900 | Brekke LTD | 350000 | 490000 | 0.04 | 75 | 10 | 27 | 2015 | TRUE | 2015/10/27 |
4 | 651029 | Harbor Co | 15000 | 12750 | -0.15 | 0 | 2 | 2 | 2014 | FALSE | 2014/2/2 |
データ型を見てみると、bool型に変換できていることがわかります。
変換後のデータフレームは以下のようになりました。
“Active”はTRUEとFALSEに変換されました。
処理をまとめる
これまでの処理は、PandasにCSVを読み込む際にまとめて記述することができます。
単純に型を変換するだけの列は引数dtypeに、加工処理を加える際は引数converterで処理を記述します。
import pandas as pd
import numpy as np
df = pd.read_csv("input/sales_data_types.csv",
dtype={'Customer Number':'int'},
converters={'2016': lambda x: float(x.replace('$', '').replace(',', '')),
'2017': lambda x: float(x.replace('$', '').replace(',', '')),
'Percent Growth': lambda x: float(x.replace('%', ''))/100,
'Jan Units': lambda x: pd.to_numeric(x, errors='coerce'),
'Active': lambda x: np.where(x == "Y", True, False)
})
こうすることで、各列でどのような変換処理をしているのかがわかりやすくなりますね。
Pythonでデータサイエンスするなら
Pythonでデータサイエンスをするなら、以下の書籍がおすすめです。Pandas、matplotlib、Numpy、scikit-learnといったデータサイエンスに必要なライブラリを、体系立てて一通り学ぶことができます。
ややお値段高めですが、これ1冊で十分という内容・ボリュームなので、損はしないと思います^^
初学者の方にはこちらもオススメです^^
まとめ
Pandasのデータフレームのデータフレームを変換する方法を紹介しました。例に挙げたデータのように、そのままでは分析に使えないといったケースは少なくありません。
分析を始めて思いもよらいないエラーを回避するためにも、最初にデータ型の確認、変換を実施してください。
ではでは👋