2日目:データ分析の強力な味方!Pandas徹底活用術(データ読み込み・整形)
皆さん、こんにちは!AI学習ロードマップ2日目です。昨日はPythonの基本的なデータ構造と、NumPyによる効率的な配列操作について学びました。今日は、実際のAIプロジェクトで最も頻繁に遭遇するであろう「表形式データ」を扱うための強力なライブラリ、Pandasに焦点を当てます。
特に、データ分析の第一歩であり、AIモデルの成否を左右すると言っても過言ではない「データの読み込みと整形」に焦点を当てて、実践的な活用術を徹底解説していきます。AI企業で働く上では、生のデータをいかに効率よく、正確に、そして目的に合わせて整形できるかが問われます。
本記事では、単にpd.read_csv()
を使うだけでなく、様々なオプションや、読み込んだ後の基本的なデータ整形テクニックまで、AI開発の現場で役立つ知識を5000文字程度のボリュームでご紹介します。
1. AI開発におけるPandasの役割と重要性
AIモデルは「データ」から学習します。しかし、ほとんどの生データはそのままではモデルに投入できません。欠損値があったり、フォーマットが不揃いだったり、人間が読みやすい形式であっても機械学習モデルにとっては理解しにくい形式であることがあります。
ここでPandasが登場します。Pandasは、表形式データを扱うためのデファクトスタンダードであり、以下のような重要な役割を担います。
- データ読み込み: CSV, Excel, データベース, JSONなど、様々な形式のデータを柔軟に読み込む。
- データ探索 (EDA - Exploratory Data Analysis): データの概要統計、分布、相関などを把握し、データの特性を理解する。
- データ整形 (Data Wrangling/Munging): 欠損値処理、重複削除、データ型の変換、列名の変更、行・列の追加/削除など、データをモデルが扱いやすい形にクリーンアップする。
- 特徴量エンジニアリング (Feature Engineering): 既存のデータから新しい有益な特徴量を作成する。
- データ集計と変換: グループ化、ピボット、マージなど、複雑なデータ変換を行う。
今日の目標は、この中でも特に重要な「データの読み込み」と「基本的な整形」をマスターすることです。
2. データ読み込みの基本と応用:read_csv()
を使いこなす
AIプロジェクトで最もよく使われるデータ形式の一つがCSV (Comma Separated Values) です。Pandasのread_csv()
関数は非常に高機能で、多くのオプションを持っています。
2.1. 基本的な読み込み
import pandas as pd
# 例として架空のデータファイルを作成
csv_data = """Name,Age,City,Score
Alice,24,New York,85
Bob,27,Los Angeles,92
Charlie,22,Chicago,78
David,32,Houston,60
Eve,29,New York,95"""
with open("sample_data.csv", "w") as f:
f.write(csv_data)
# CSVファイルを読み込む
df = pd.read_csv("sample_data.csv")
print("--- 基本的なデータ読み込み ---")
print(df)
print("\n")
2.2. ファイルパスと文字エンコーディング
-
ファイルパス: 相対パス、絶対パス、URL(ウェブ上のCSVファイル)を指定できます。
-
encoding
: 日本語を含むCSVファイルなど、文字化けを避けるために適切なエンコーディングを指定することが非常に重要です。'utf-8'
,'shift_jis'
,'cp932'
,'euc-jp'
などがよく使われます。# encodingを指定 # df_jp = pd.read_csv("japanese_data.csv", encoding='shift_jis') # print(df_jp)
2.3. ヘッダー行の指定 (header
, names
)
データにヘッダー行がない場合や、独自の列名を付けたい場合に指定します。
# ヘッダー行がないCSVファイルの場合
csv_no_header = """Alice,24,New York,85
Bob,27,Los Angeles,92"""
with open("no_header_data.csv", "w") as f:
f.write(csv_no_header)
df_no_header = pd.read_csv("no_header_data.csv", header=None) # ヘッダーなしを指定
print("--- ヘッダーなしのデータ読み込み ---")
print(df_no_header)
# 独自の列名を指定
df_custom_header = pd.read_csv(
"no_header_data.csv",
header=None,
names=['PersonName', 'YearsOld', 'Location', 'ResultScore']
)
print("--- 独自の列名を指定して読み込み ---")
print(df_custom_header)
print("\n")
2.4. 区切り文字の指定 (sep
/ delimiter
)
CSVファイルがカンマ以外の区切り文字(タブ、セミコロンなど)を使用している場合に指定します。
# タブ区切りファイル
tsv_data = """Name\tAge\tCity
Alice\t24\tNew York
Bob\t27\tLos Angeles"""
with open("tab_data.tsv", "w") as f:
f.write(tsv_data)
df_tsv = pd.read_csv("tab_data.tsv", sep='\t') # タブ区切りを指定
print("--- タブ区切りファイルの読み込み ---")
print(df_tsv)
print("\n")
2.5. インデックス列の指定 (index_col
)
特定の列をデータフレームのインデックスとして使用したい場合に指定します。
df_indexed = pd.read_csv("sample_data.csv", index_col='Name')
print("--- 'Name'列をインデックスとして読み込み ---")
print(df_indexed)
print("\n")
AIモデルの学習においては、通常は自動生成される0からの整数インデックスで問題ありませんが、データの特定行にアクセスする際に名前などで指定したい場合に便利です。
2.6. 特定の列のみを読み込む (usecols
)
非常に大きなデータファイルで、一部の列しか必要ない場合にメモリと時間を節約できます。
df_partial = pd.read_csv("sample_data.csv", usecols=['Name', 'Score'])
print("--- 'Name'と'Score'列のみ読み込み ---")
print(df_partial)
print("\n")
2.7. 欠損値の扱い (na_values
, keep_default_na
)
Pandasはデフォルトで空文字列や特定の文字列('NA', 'NaN'など)を欠損値(NaN)として扱いますが、独自の文字列を欠損値として認識させたい場合にna_values
を使います。
csv_na = """Product,Price,Quantity
A,100,5
B,,10
C,200,NaN
D,300,-""" # '-'を欠損値として扱いたい
with open("na_data.csv", "w") as f:
f.write(csv_na)
df_na = pd.read_csv("na_data.csv", na_values=['', '-']) # 空文字列と'-'をNaNとして扱う
print("--- 欠損値を指定して読み込み ---")
print(df_na)
print("\n")
データソースによっては「不明」「該当なし」といった文字列が欠損値を表すことがあります。これらを正しくNaNとして読み込むことは、後の欠損値処理において非常に重要です。
2.8. 大規模データのチャンク読み込み (chunksize
)
メモリに収まりきらないような非常に大きなファイルを扱う場合、一度に全て読み込むのではなく、チャンク(塊)に分割して読み込むことができます。
# 仮に非常に大きなファイルがあるとして
for chunk in pd.read_csv("large_data.csv", chunksize=10000):
# # 各チャンクに対して処理を行う
# # 例: chunk.dropna(inplace=True)
# # 例: process_and_save_chunk(chunk)
# pass
print("--- 大規模データのチャンク読み込み完了 ---")
AI開発で数GB〜数TBのデータを扱う際には、このテクニックが必須になることがあります。
3. データの基本的な整形術
データを読み込んだら、次に待っているのは「整形」です。AIモデルがデータを正しく解釈し、効率的に学習するためには、データがクリーンで一貫した形式であることが不可欠です。
3.1. データの概要把握 (.info()
, .describe()
, .head()
, .tail()
)
整形を始める前に、まずはデータの全体像を把握しましょう。
print("--- データフレームの基本情報 (.info()) ---")
df.info() # 各列のデータ型、欠損値の有無、メモリ使用量などがわかる
print("\n")
print("--- 数値列の要約統計量 (.describe()) ---")
print(df.describe()) # 統計量 (平均、標準偏差、最小/最大値など)
print("\n")
print("--- 最初の5行 (.head()) ---")
print(df.head())
print("\n")
print("--- 最後の5行 (.tail()) ---")
print(df.tail())
print("\n")
これらのメソッドは、データ探索(EDA)の初期段階で非常に役立ちます。特に.info()
は、思わぬ型変換(数値が文字列として読み込まれているなど)や、欠損値の概数を知るのに重要です。
3.2. 列名の変更 (.columns
, .rename()
)
列名が不適切だったり、長すぎたり、特殊文字を含んでいたりすると、コードが読みにくくなったり、エラーの原因になったりします。
# 全ての列名を一括で変更
df.columns = ['Full Name', 'AgeYears', 'City_Location', 'Exam_Score']
print("--- 列名の一括変更 ---")
print(df)
print("\n")
# 特定の列名のみを変更 (.rename())
df.rename(columns={'Full Name': 'Name', 'Exam_Score': 'Score'}, inplace=True)
print("--- 特定の列名のみ変更 ---")
print(df)
print("\n")
inplace=True
は、元のデータフレームを直接変更する場合に指定します。指定しない場合、変更された新しいデータフレームが返されます。
3.3. データ型の変換 (.astype()
)
数値列が文字列として読み込まれてしまったり、メモリ効率のためにデータ型を変更したい場合にastype()
を使用します。
# Score列のデータ型を確認
print(f"元の'Score'列の型: {df['Score'].dtype}")
# Score列をint型に変換
df['Score'] = df['Score'].astype(int)
print(f"変換後の'Score'列の型: {df['Score'].dtype}")
# カテゴリカルデータ型への変換 (メモリ効率と処理速度の向上)
# 例: City列はユニークな値が少ないため、category型が適している
df['City_Location'] = df['City_Location'].astype('category')
print(f"変換後の'City_Location'列の型: {df['City_Location'].dtype}")
print("--- データ型の変換 ---")
print(df)
print("\n")
category
型への変換は、特にユニークな値が少ない文字列カラムにおいて、メモリ使用量を大幅に削減し、一部の操作の速度を向上させる効果があります。AIモデルにカテゴリカルデータを投入する前処理としても重要です。
3.4. 欠損値の処理 (.isnull()
, .fillna()
, .dropna()
)
データの品質を保つ上で最も重要な作業の一つです。
# 欠損値を含むデータフレームの例を再利用
csv_na_extended = """Product,Price,Quantity,Description
A,100,5,Good
B,,10,
C,200,NaN,Best
D,300,-,Average
E,400,20,Excellent""" # QuantityにNaNと-、Descriptionに空文字列がある
with open("na_data_extended.csv", "w") as f:
f.write(csv_na_extended)
df_na_ext = pd.read_csv("na_data_extended.csv", na_values=['', '-']) # 空文字列と'-'をNaNとして扱う
print("--- 欠損値を含むデータフレーム ---")
print(df_na_ext)
# 各列の欠損値の数
print("\n--- 各列の欠損値の数 ---")
print(df_na_ext.isnull().sum())
# 欠損値がある行を削除
df_cleaned_drop = df_na_ext.dropna()
print("\n--- 欠損値を含む行を削除 (.dropna()) ---")
print(df_cleaned_drop)
# 特定の列にのみ欠損値がある行を削除
df_cleaned_drop_subset = df_na_ext.dropna(subset=['Price'])
print("\n--- 'Price'列に欠損値がある行を削除 (.dropna(subset=['Price'])) ---")
print(df_cleaned_drop_subset)
# 欠損値を特定の値で埋める
# Price列の欠損値を平均値で埋める
df_filled_mean = df_na_ext.copy() # 元のDFを壊さないようにコピー
df_filled_mean['Price'] = df_filled_mean['Price'].fillna(df_filled_mean['Price'].mean())
print("\n--- 'Price'列の欠損値を平均値で埋める (.fillna(mean)) ---")
print(df_filled_mean)
# Quantity列の欠損値を中央値で埋める
df_filled_median = df_na_ext.copy()
df_filled_median['Quantity'] = df_filled_median['Quantity'].fillna(df_filled_median['Quantity'].median())
print("\n--- 'Quantity'列の欠損値を中央値で埋める (.fillna(median)) ---")
print(df_filled_median)
# Description列の欠損値を最頻値で埋める (または'Unknown'などの文字列で埋める)
df_filled_mode = df_na_ext.copy()
df_filled_mode['Description'] = df_filled_mode['Description'].fillna('Unknown')
print("\n--- 'Description'列の欠損値を'Unknown'で埋める (.fillna('Unknown')) ---")
print(df_filled_mode)
print("\n")
欠損値の処理方法は、データの性質やAIモデルの要求によって異なります。単純に削除するか、平均値、中央値、最頻値、あるいは別のモデルで予測して補完するか、慎重に選択する必要があります。
3.5. 重複行の削除 (.duplicated()
, .drop_duplicates()
)
データセット内に完全に一致する重複行が存在する場合、これらはモデルの学習を歪める可能性があります。
# 重複データを含むデータフレームの例
duplicated_data = """Name,Age,City
Alice,24,New York
Bob,27,Los Angeles
Alice,24,New York
Charlie,22,Chicago
Bob,27,Los Angeles"""
with open("duplicated_data.csv", "w") as f:
f.write(duplicated_data)
df_dup = pd.read_csv("duplicated_data.csv")
print("--- 重複を含むデータフレーム ---")
print(df_dup)
# 重複行の確認 (True:重複, False:ユニーク)
print("\n--- 重複行の確認 (.duplicated()) ---")
print(df_dup.duplicated())
# 重複行を削除 (デフォルトでは最初の行を残す)
df_no_dup = df_dup.drop_duplicates()
print("\n--- 重複行を削除 (.drop_duplicates()) ---")
print(df_no_dup)
# 特定の列の組み合わせに基づいて重複を削除
df_no_dup_subset = df_dup.drop_duplicates(subset=['Name', 'City'])
print("\n--- 'Name'と'City'の組み合わせで重複を削除 ---")
print(df_no_dup_subset)
print("\n")
drop_duplicates()
のsubset
引数は、特定の列の組み合わせで重複を判断したい場合に非常に便利です。keep
引数('first'
, 'last'
, False
)で、重複する行のどれを残すかを指定できます。
4. まとめと次へのステップ
本日は、AI学習ロードマップの2日目として、Pandasを用いたデータの読み込みと整形について深く掘り下げました。
- **
pd.read_csv()
**は、AIプロジェクトで最も頻繁に使う関数の一つであり、encoding
,header
,sep
,index_col
,usecols
,na_values
,chunksize
などの豊富なオプションを使いこなすことで、様々な形式の生データを効率的かつ正確に読み込めます。 - 読み込んだ後のデータ整形では、**
.info()
,.describe()
,.head()
**などでデータを把握し、列名の変更、データ型の変換、欠損値の処理、重複行の削除といった基本的なテクニックが不可欠です。これらの処理を適切に行うことで、AIモデルがデータからより良いパターンを学習し、高精度な結果を出すための土台が築かれます。
これらのスキルは、今後のAI学習のあらゆる段階であなたの強力な武器となります。特に、明日以降の「データ可視化」や「特徴量エンジニアリング」に進む前に、今日の知識をしっかりと身につけておくことをお勧めします。
明日は、今日整形したデータを「可視化」することで、データの隠れたパターンや関係性を発見する方法について学びます。データは語ります。その声を聞き取るための力を養いましょう。
それでは、また明日!