Pandas分析の前処理 データ型(dtypes)の確認と適切な変換(astype)の方法

こんにちは。これまでの記事で、Pandas DataFrameの基本的な操作(データの確認、列・行の選択、欠損値処理、重複処理など)を一通り学んできました。データのお掃除も進み、いよいよ本格的な分析や加工に進む準備が整いつつありますね。

さて、データ分析を進める上で、見落としがちながら非常に重要なのが「データ型(データタイプ)」です。データ型とは、そのデータがどのような種類か(数値なのか、文字列なのか、日付なのかなど)を示す「ラベル」のようなものです。

なぜデータ型が重要なのでしょうか? それは、データ型によって、そのデータに対して行える操作や計算が異なるからです。例えば、数値データであれば四則演算や大小比較ができますが、文字列データに同じ操作をしようとしても意味がありません(あるいはエラーになります)。また、データが意図しない型になっていると、メモリを無駄に消費したり、処理速度が遅くなったり、後々の分析や機械学習モデルの構築で問題を引き起こしたりすることもあります。

そこで今回は、データ分析をスムーズに進めるための基礎として、以下の内容を学びます。

  • Pandasにおける主なデータ型とその意味を再確認する。
  • DataFrameの各列のデータ型を確認する方法(.dtypes属性)。
  • 特定の列のデータ型を、目的に合わせて適切な型に変換する方法(.astype()メソッド)。
  • 数値に見える文字列を数値型に、数値を文字列型に、メモリ効率の良いカテゴリ型になど、具体的な型変換の例を見る。
  • 型変換時に起こりうるエラーとその対処法のヒントを得る。

データ型を意識し、適切に扱うことは、効率的で正確なデータ分析を行うための土台となります。一見地味なテーマかもしれませんが、非常に重要なスキルですので、しっかりマスターしていきましょう。

Pandasの主なデータ型(おさらい)

まずは、Pandasでよく使われる基本的なデータ型をおさらいしておきましょう。以前info()メソッドの解説でも触れましたが、改めて確認します。

  • object: 主に文字列 (string) を格納するために使われる型です。数値と文字列が混在している場合などもこの型になることがあります。非常に柔軟ですが、数値計算などは直接行えませんし、メモリ効率も他の型に比べて良くない場合があります。
  • int64: 整数 (integer) を格納する型です。64は通常、データを表現するのに使うビット数を指します(他にもint8, int16, int32などがありますが、通常はint64がデフォルトです)。
  • float64: 浮動小数点数 (floating-point number)、つまり小数を含む数値を格納する型です。こちらも64ビットが一般的です。欠損値NaNを含む数値列は、自動的にこのfloat64型になることが多いです。
  • bool: 真偽値 (boolean) を格納する型で、True (真) または False (偽) のどちらかの値をとります。条件判定の結果などで使われます。
  • datetime64[ns]: 日付と時刻 を格納するための専用の型です。'2023-11-15''2023-11-15 10:30:00'のようなデータを効率的に扱い、日付関連の計算(期間計算など)を行うのに便利です。
  • category: カテゴリカルデータ(順序のない、または順序のある限られた種類の値をとるデータ。例:血液型、曜日、アンケートの評価段階「良い/普通/悪い」など)を効率的に格納するための型です。特に、同じ文字列が繰り返し現れるような列をこの型に変換すると、メモリ使用量を大幅に削減でき、一部の処理が高速になることがあります。

これらのデータ型を意識し、各列が意図した通りの型になっているかを確認することが重要です。

サンプルデータの準備(様々な型を含む)

データ型の確認と変換をデモンストレーションするために、少し工夫したサンプルDataFrameを作成します。数値に見えるけれど実は文字列になっているデータや、カテゴリデータとして扱えそうなデータを含めてみましょう。

import pandas as pd
import numpy as np

# 様々なデータ型(と、意図しない型)を含むサンプルデータ
data_types = {
    '商品ID': [101, 102, 103, 104, 105],       # 本来は数値だが、IDとして文字列で扱いたい場合もある
    '商品名': ['リンゴ', 'バナナ', 'ミカン', 'リンゴ', 'ブドウ'], # 文字列(object)
    '価格(円)': ['150', '80', '120', '160', '300'], # 数値に見えるが文字列(object)になっている
    '在庫数': [50, 100, np.nan, 80, 30],        # 欠損値を含むためfloat64になる
    '評価': ['良い', '普通', '良い', '最高', '普通'],      # カテゴリデータとして扱えそう(object)
    '販売フラグ': [True, False, True, True, False] # ブール値(bool)
}

df_types = pd.DataFrame(data_types)

# 作成したDataFrameを表示
print("--- サンプルDataFrame (型変換前) ---")
print(df_types)

実行結果:

--- サンプルDataFrame (型変換前) ---
   商品ID 商品名 価格(円)  在庫数    評価  販売フラグ
0    101  リンゴ   150   50.0    良い    True
1    102  バナナ    80  100.0    普通   False
2    103  ミカン   120    NaN    良い    True
3    104  リンゴ   160   80.0    最高    True
4    105  ブドウ   300   30.0    普通   False

このDataFrameには、以下のような特徴があります。

  • 「商品ID」: 見た目は数値ですが、整数(int)型です。場合によっては文字列(str)として扱いたいかもしれません。
  • 「価格(円)」: 見た目は数値ですが、辞書作成時に文字列' 'で囲んだため、文字列(object)型として読み込まれています。このままでは数値計算ができません。
  • 「在庫数」: 欠損値np.nanを含んでいるため、Pandasによって自動的に浮動小数点数(float64)型になっています。
  • 「評価」: ‘良い’, ‘普通’, ‘最高’ といった限られた種類の文字列が含まれており、カテゴリ(category)型に変換すると効率が良さそうです。

これらの列のデータ型を実際に確認し、変換していきましょう。

データ型の確認:.dtypes 属性

DataFrameの各列のデータ型を確認するには、すでにお馴染みの.dtypes属性を使います。

# 各列のデータ型を確認
print(df_types.dtypes)

実行結果:

商品ID         int64
商品名         object
価格(円)       object
在庫数       float64
評価          object
販売フラグ         bool
dtype: object

実行結果を見ると、

  • 「商品ID」はint64(整数)。
  • 「商品名」「評価」はobject(文字列)。
  • 「価格(円)」は、予想通りobject(文字列)になっています(赤色で強調)。これは問題です!
  • 「在庫数」はfloat64(浮動小数点数)。
  • 「販売フラグ」はbool(ブール値)。

であることが確認できました。「価格(円)」が文字列型になっているため、このままでは価格の合計や平均を計算することができません。これを数値型に変換する必要がありますね。また、「評価」列もカテゴリ型に変換できそうです。

データ型の変換:.astype() メソッド

特定の列のデータ型を変換するには、.astype()メソッドを使います。このメソッドは、Series(DataFrameの1列)またはDataFrame全体に対して適用できます。

基本的な使い方は、変換したい列(Series)の後ろに.astype(変換後のデータ型)と記述します。変換後のデータ型は、文字列(例: 'int', 'float', 'str', 'category')や、NumPyのデータ型(例: np.int64, np.float64)などで指定します。

文字列を数値に変換 (int, float)

最もよく行う型変換の一つが、文字列として読み込まれてしまった数値を、計算可能な数値型(整数intまたは浮動小数点数float)に変換する操作です。「価格(円)」列で試してみましょう。

# '価格(円)'列を整数(int)型に変換
# まずはSeriesとして変換を試みる
price_int_series = df_types['価格(円)'].astype(int)
print("--- '価格(円)'列 (int型に変換後) ---")
print(price_int_series)

実行結果:

--- '価格(円)'列 (int型に変換後) ---
0    150
1     80
2    120
3    160
4    300
Name: 価格(円), dtype: int64

見た目は変わりませんが、データ型がdtype: int64となり、正しく整数型に変換されました。これで、この列を使って合計や平均などの計算ができるようになります。

DataFrameに反映させるには?
.astype()も、デフォルトでは元のDataFrameを変更せず、変換後のSeries(またはDataFrame)を返します。変換結果を元のDataFrameに反映させたい場合は、上書き代入を行います。

# 元のDataFrameの'価格(円)'列をint型で上書き
df_types['価格(円)'] = df_types['価格(円)'].astype(int)

# 念のため、変換後のDataFrame全体の型を確認
print("--- DataFrame全体の型 (価格(円)変換後) ---")
print(df_types.dtypes)

実行結果:

--- DataFrame全体の型 (価格(円)変換後) ---
商品ID         int64
商品名         object
価格(円)       int64
在庫数       float64
評価          object
販売フラグ         bool
dtype: object

「価格(円)」列のデータ型がint64に変わっていることが確認できました。

浮動小数点数 (float) への変換
もし小数点を含む可能性のある文字列(例: '150.5')を変換する場合は、intではなくfloatを指定します。

# 例:もし小数点が含まれていたらfloat型に変換
# df_types['列名'].astype(float)

数値を文字列に変換 (str or object)

逆に、数値を文字列として扱いたい場合もあります。例えば、「商品ID」は数値ですが、足し算や引き算をする対象ではなく、単なる識別子として扱いたい場合などです。このような場合、文字列型に変換しておくと、意図しない計算を防ぐことができます。

# '商品ID'列を文字列(str)型に変換
df_types['商品ID'] = df_types['商品ID'].astype(str)

# 変換後の型を確認
print("--- DataFrame全体の型 (商品ID変換後) ---")
print(df_types.dtypes)

実行結果:

--- DataFrame全体の型 (商品ID変換後) ---
商品ID        object
商品名         object
価格(円)       int64
在庫数       float64
評価          object
販売フラグ         bool
dtype: object

「商品ID」列のデータ型がobject(文字列)に変わりました。(Pandasでは.astype(str)と指定すると、object型として扱われることが多いです。)

カテゴリ型への変換 (category)

「評価」列のように、取りうる値の種類が限られている文字列データは、category型に変換することでメモリ効率を高めることができます。

# '評価'列をカテゴリ(category)型に変換
df_types['評価'] = df_types['評価'].astype('category')

# 変換後の型を確認
print("--- DataFrame全体の型 (評価変換後) ---")
print(df_types.dtypes)

# カテゴリ型の情報を少し見てみる(おまけ)
print("\n--- '評価'列のカテゴリ情報 ---")
print(df_types['評価'].cat.categories) # どのようなカテゴリがあるか
print(df_types['評価'].cat.codes)      # 各行がどのカテゴリ番号に対応するか

実行結果:

--- DataFrame全体の型 (評価変換後) ---
商品ID         object
商品名         object
価格(円)       int64
在庫数       float64
評価        category
販売フラグ         bool
dtype: object

--- '評価'列のカテゴリ情報 ---
Index(['良い', '普通', '最高'], dtype='object')
0    0
1    1
2    0
3    2
4    1
dtype: int8

「評価」列のデータ型がcategoryに変わりました。内部的には、「良い」「普通」「最高」という文字列そのものではなく、それぞれに対応する整数コード(0, 1, 2)でデータが保持されるため、メモリ使用量が削減されます。特にデータ量が大きい場合に効果を発揮します。

複数の列をまとめて変換

複数の列のデータ型を一度に変換したい場合は、DataFrame全体に対して.astype()を適用し、引数に辞書を渡します。辞書のキーに列名、値に変換したいデータ型を指定します。

例えば、もしdf_typesがまだ変換されていない状態だったとして、「価格(円)」をintに、「評価」をcategoryに同時に変換するには、次のように書けます。

# (もし変換前に戻すなら)元のDataFrameを再作成
# df_types = pd.DataFrame(data_types) 

# 複数の列の型を同時に変換
df_types_multi = df_types.astype({
    '価格(円)': int,
    '評価': 'category',
    '商品ID': str # ついでに商品IDも文字列に
})

# 変換後の型を確認
print("--- 複数列をまとめて型変換後 ---")
print(df_types_multi.dtypes)

実行結果:

--- 複数列をまとめて型変換後 ---
商品ID         object
商品名         object
価格(円)       int64
在庫数       float64
評価        category
販売フラグ         bool
dtype: object

指定した列の型が一度に変換されました。この方法は、多くの列の型を修正したい場合に便利です。

型変換時のエラーとその対処

.astype()を使って型変換を行う際、特に文字列を数値に変換しようとする場合に、エラーが発生することがあります。最もよく遭遇するのがValueErrorです。

これは、変換先の型として解釈できない値が列に含まれている場合に発生します。

エラー発生例:数値に変換できない文字が含まれる場合
例えば、「価格(円)」列に'150円'のように単位が含まれていたり、'--'のような記号が入っていたりすると、そのままではintfloatに変換できません。

# エラー発生例:数値に変換できない文字列を含むデータ
error_data = {'価格': ['100', '200円', '300']}
df_error = pd.DataFrame(error_data)
print("--- エラー発生前のDataFrame ---")
print(df_error)

try:
    # int型への変換を試みる → エラーが発生するはず
    df_error['価格'].astype(int)
except ValueError as e:
    print(f"\n--- エラー発生 ---")
    print(e) # エラーメッセージを表示

実行結果:

--- エラー発生前のDataFrame ---
      価格
0    100
1   200円
2    300

--- エラー発生 ---
invalid literal for int() with base 10: '200円'

'200円'という文字列は整数(int)として解釈できないため、ValueErrorが発生しました。

エラーへの対処法:前処理を行う
このようなエラーが発生した場合、.astype()を適用するに、問題のある文字を取り除くなどの前処理が必要になります。

具体的な前処理の方法(文字列の置換.str.replace()など)については、今後の文字列操作に関する記事で詳しく解説しますが、基本的な考え方としては、

  1. 変換できない原因となっている文字(例:「円」)を特定する。
  2. その文字を空文字('')などに置換して取り除く。
  3. 不要な文字がなくなった状態で、.astype()を使って数値型に変換する。

という手順を踏みます。

データクリーニングにおいては、このように型変換エラーからデータの不備を発見し、適切な前処理を行う、というサイクルを繰り返すことがよくあります。

まとめ

今回は、Pandas DataFrameにおけるデータ型の確認と変換について学びました。

  • データ型の重要性: データ型によって実行できる操作が異なり、分析の正確性や効率に影響するため、各列が適切な型になっているかを確認・修正することが重要。
  • 主なデータ型: object(文字列), int64(整数), float64(小数), bool(真偽値), datetime64(日付時刻), category(カテゴリ)など。
  • データ型の確認: .dtypes属性を使うことで、DataFrameの各列のデータ型を一覧表示できる。
  • データ型の変換: .astype(変換したい型)メソッドを使う。
    • 文字列を数値に変換: .astype(int), .astype(float)
    • 数値を文字列に変換: .astype(str)
    • カテゴリ型に変換: .astype('category')(メモリ効率向上)
    • 複数列をまとめて変換: .astype({'列名1': 型1, '列名2': 型2})
  • 型変換エラー: 変換先の型として解釈できない値(例: 数値以外の文字を含む文字列を数値に変換しようとした場合)があるとValueErrorが発生する。エラー発生時は、.astype()の前に不要な文字を除去するなどの前処理が必要。
  • .astype()の注意点: デフォルトでは元のDataFrameを変更せず、変換後のデータを返す。元のDataFrameに反映させるには上書き代入が必要。

データ型を正しく理解し、適切に変換するスキルは、Pandasを使ったデータ操作の基礎となります。.dtypesで現状を確認し、必要に応じて.astype()で修正する、という流れを意識して、データ分析を進めていきましょう。

次回予告

データクリーニング(欠損値処理、重複処理、型変換)の基本的なステップを終え、データがかなり扱いやすくなってきました。ここからは、データをより深く理解し、分析の準備を整えるためのテクニックを学んでいきます。

次回は、特定のカテゴリごとにデータを集約して分析する「グループ集計」について詳しく解説します。Pandasの.groupby()メソッドを使って、「部署ごとの平均年齢」「商品ごとの売上合計」などを簡単に計算する方法をマスターしましょう。データからより多くの洞察を得るための強力な武器となります!お楽しみに!