PandasとNumpyを使った初心者向けデータ分析手法

## はじめに

NumPyとPandasは、Pythonのデータ分析において非常に重要なライブラリです。この記事では、30件のデータを使用して、これらのライブラリの基本的な使い方から高度な機能まで、段階的に解説していきます。初心者の方にも分かりやすく、実践的な例を交えながら説明していきますので、ぜひ最後までお付き合いください。

## 第1章: データの準備

まずは、分析に使用するデータを準備しましょう。今回は、架空の学生データを使用します。このデータには、学生の名前、年齢、成績、出席率などの情報が含まれています。

```python
import numpy as np
import pandas as pd

# 30件の学生データを作成
data = {
    '名前': ['田中太郎', '山田花子', '佐藤一郎'] * 10,
    '年齢': np.random.randint(18, 25, 30),
    '成績': np.random.choice(['A', 'B', 'C', 'D'], 30),
    '出席率': np.random.uniform(0.6, 1.0, 30)
}

# DataFrameの作成
df = pd.DataFrame(data)
print(df.head())
```

このコードでは、NumPyの`random`モジュールを使用してランダムなデータを生成し、Pandasの`DataFrame`オブジェクトを作成しています。`head()`メソッドを使用して、最初の5行のデータを表示しています。

## 第2章: NumPyの基本

NumPyは、多次元配列を効率的に扱うためのライブラリです。ここでは、NumPyの基本的な使い方を学びます。

```python
# NumPy配列の作成
ages = np.array(df['年齢'])

# 基本的な統計量の計算
print(f"平均年齢: {np.mean(ages):.2f}")
print(f"最小年齢: {np.min(ages)}")
print(f"最大年齢: {np.max(ages)}")
print(f"年齢の標準偏差: {np.std(ages):.2f}")

# 条件に基づいた要素の選択
young_students = ages[ages < 20]
print(f"20歳未満の学生数: {len(young_students)}")
```

このコードでは、DataFrameから年齢のデータを取り出してNumPy配列を作成し、基本的な統計量を計算しています。また、条件に基づいて要素を選択する方法も示しています。NumPyの強力な機能により、大量のデータを効率的に処理することができます。

## 第3章: Pandasの基本操作

Pandasは、表形式のデータを扱うための強力なツールです。ここでは、Pandasの基本的な操作方法を学びます。

```python
# 基本的な情報の表示
print(df.info())

# 統計情報の表示
print(df.describe())

# 特定の列の選択
print(df['成績'].value_counts())

# 複数の列の選択
print(df[['名前', '年齢']])

# 条件に基づく行の選択
print(df[df['出席率'] > 0.8])

# ソート
print(df.sort_values('年齢', ascending=False))
```

このコードでは、DataFrameの基本的な情報の表示、統計情報の表示、特定の列や行の選択、データのソートなど、Pandasの基本的な操作方法を示しています。これらの操作を使いこなすことで、データの探索や前処理を効率的に行うことができます。

## 第4章: データの可視化

データを視覚化することで、データの傾向や特徴を直感的に理解することができます。ここでは、Matplotlib

を使用してデータを可視化する方法を学びます。

```python
import matplotlib.pyplot as plt

# 年齢のヒストグラム
plt.figure(figsize=(10, 6))
plt.hist(df['年齢'], bins=10, edgecolor='black')
plt.title('学生の年齢分布')
plt.xlabel('年齢')
plt.ylabel('人数')
plt.show()

# 成績の円グラフ
plt.figure(figsize=(8, 8))
df['成績'].value_counts().plot(kind='pie', autopct='%1.1f%%')
plt.title('成績の分布')
plt.ylabel('')
plt.show()

# 年齢と出席率の散布図
plt.figure(figsize=(10, 6))
plt.scatter(df['年齢'], df['出席率'])
plt.title('年齢と出席率の関係')
plt.xlabel('年齢')
plt.ylabel('出席率')
plt.show()
```

このコードでは、年齢のヒストグラム、成績の円グラフ、年齢と出席率の散布図を作成しています。これらのグラフを通じて、データの分布や関係性を視覚的に理解することができます。

## 第5章: データの集計

データの集計は、大量のデータから有用な情報を抽出するための重要な操作です。ここでは、Pandasを使用してデータを集計する方法を学びます。

```python
# 成績ごとの平均年齢と平均出席率
print(df.groupby('成績')[['年齢', '出席率']].mean())

# 年齢層ごとの成績分布
df['年齢層'] = pd.cut(df['年齢'], bins=[0, 20, 22, 25], labels=['18-20', '21-22', '23-25'])
print(pd.crosstab(df['年齢層'], df['成績']))

# 複数の列でグループ化
print(df.groupby(['年齢層', '成績'])['出席率'].mean().unstack())
```

このコードでは、`groupby`メソッドを使用して成績ごとの統計を計算し、`cut`関数で年齢を区分けし、`crosstab`関数でクロス集計を行っています。これらの操作を通じて、データの傾向や特徴をより詳細に把握することができます。

## 第6章: データの結合

複数のデータセットを結合することで、より豊富な情報を得ることができます。ここでは、Pandasを使用してデータを結合する方法を学びます。

```python
# 新しいデータフレームの作成
extra_data = pd.DataFrame({
    '名前': ['田中太郎', '山田花子', '佐藤一郎'] * 10,
    '部活': np.random.choice(['野球部', 'サッカー部', '吹奏楽部', '無所属'], 30)
})

# データの結合
merged_df = pd.merge(df, extra_data, on='名前')
print(merged_df.head())

# 部活ごとの平均年齢と平均出席率
print(merged_df.groupby('部活')[['年齢', '出席率']].mean())
```

このコードでは、`merge`関数を使用して2つのDataFrameを結合しています。結合されたデータを使用して、部活ごとの統計を計算しています。データの結合により、より多角的な分析が可能になります。

## 第7章: 欠損値の処理

実際のデータには欠損値が含まれていることがよくあります。ここでは、欠損値の処理方法を学びます。

```python
# 欠損値の作成
df.loc[np.random.choice(df.index, 5), '出席率'] = np.nan

# 欠損値の確認
print(df.isnull().sum())

# 欠損値の補完
df['出席率'].fillna(df['出席率'].mean(), inplace=True)

# 欠損値の削除
df_dropped = df.dropna()

print("欠損値補完後のデータ数:", len(df))
print("欠損値削除後のデータ数:", len(df_dropped))
```

このコードでは、意図的に欠損値を作成し、`isnull()`メソッドで欠損値を確認しています。その後、`fillna()`メソッドで欠損値を平均値で補完し、`dropna()`メソッドで欠損値を含む行を削除しています。欠損値の適切な処理は、分析結果の信頼性を高めるために重要です。

## 第8章: データの正規化

データの正規化は、異なるスケールのデータを比較可能にするために重要です。ここでは、NumPyとPandasを使用してデータを正規化する方法を学びます。

```python
# Min-Max正規化
df['出席率_正規化'] = (df['出席率'] - df['出席率'].min()) / (df['出席率'].max() - df['出席率'].min())

# Z-score正規化
df['年齢_正規化'] = (df['年齢'] - df['年齢'].mean()) / df['年齢'].std()

print(df[['出席率', '出席率_正規化', '年齢', '年齢_正規化']].head())

# 正規化前後の統計量の比較
print(df[['出席率', '出席率_正規化', '年齢', '年齢_正規化']].describe())
```

このコードでは、出席率にMin-Max正規化を、年齢にZ-score正規化を適用しています。正規化により、データのスケールが統一され、異なる特徴量間の比較が容易になります。正規化前後の統計量を比較することで、正規化の効果を確認できます。

## 第9章: 時系列データの処理

時系列データの処理は、多くのデータ分析タスクで重要です。ここでは、Pandasを使用して時系列データを扱う方法を学びます。

```python
# 日付データの生成
dates = pd.date_range(start='2023-01-01', periods=30, freq='D')
df['日付'] = dates

# 日付でインデックスを設定
df.set_index('日付', inplace=True)

# 週ごとの平均出席率
weekly_attendance = df['出席率'].resample('W').mean()
print(weekly_attendance)

# 移動平均の計算
df['出席率_移動平均'] = df['出席率'].rolling(window=7).mean()

# 時系列データの可視化
plt.figure(figsize=(12, 6))
plt.plot(df.index, df['出席率'], label='出席率')
plt.plot(df.index, df['出席率_移動平均'], label='7日移動平均')
plt.title('日々の出席率と移動平均')
plt.xlabel('日付')
plt.ylabel('出席率')
plt.legend()
plt.show()
```

このコードでは、日付データを生成し、それをインデックスとして設定しています。`resample()`メソッドを使用して週ごとの平均を計算し、`rolling()`メソッドで移動平均を計算しています。最後に、時系列データを可視化しています。これらの操作により、時間の経過に伴うデータの変化を分析することができます。

## 第10章: データのピボット

ピボットテーブルは、データを再構成して新しい視点から分析するのに役立ちます。ここでは、Pandasを使用してデータをピボットする方法を学びます。

```python
# ピボットテーブルの作成
pivot_table = pd.pivot_table(df, values='出席率', index='成績', columns='年齢層', aggfunc='mean')
print(pivot_table)

# ピボットテーブルの可視化
plt.figure(figsize=(10, 6))
pivot_table.plot(kind='bar', stacked=True)
plt.title('成績と年齢層ごとの平均出席率')
plt.xlabel('成績')
plt.ylabel('平均出席率')
plt.legend(title='年齢層')
plt.show()
```

このコードでは、`pivot_table()`関数を使用して、成績と年齢層ごとの平均出席率を計算しています。その結果を棒グラフで可視化しています。ピボットテーブルを使用することで、データの多次元的な分析が可能になります。

## 第11章: データの変換

データの変換は、分析に適した形式にデータを整形するために重要です。ここでは、Pandasを使用してデータを変換する方法を学びます。

```python
# カテゴリ変数のエンコーディング
df['成績_encoded'] = pd.Categorical(df['成績']).codes

# 新しい特徴量の作成
df['出席率_カテゴリ'] = pd.cut(df['出席率'], bins=[0, 0.7, 0.9, 1], labels=['低', '中', '高'])

# apply関数の使用
def age_category(age):
    if age < 20:
        return '10代'
    elif age < 23:
        return '早期20代'
    else:
        return '後期20代'

df['年齢カテゴリ'] = df['年齢'].apply(age_category)

print(df.head())
```

このコードでは、カテゴリ変数のエンコーディング、連続変数の離散化、カスタム関数を使用した新しい特徴量の作成など、様々なデータ変換の方法を示しています。これらの変換により、データをより分析しやすい形に整形することができます。

## 第12章: 高度なデータ操作

Pandasには、より複雑なデータ操作を行うための高度な機能があります。ここでは、これらの高度な機能について学びます。

```python
# 複数の条件に基づくデータ選択
complex_selection = df[(df['年齢'] > 20) & (df['出席率'] > 0.8) | (df['成績'] == 'A')]
print(complex_selection)

# データのリシェイプ
melted_df = pd.melt(df, id_vars=['名前', '成績'], value_vars=['年齢', '出席率'])
print(melted_df.head(10))

# 集計関数の適用
agg_result = df.groupby('成績').agg({
    '年齢': ['mean', 'min', 'max'],
    '出席率': ['mean', 'min', 'max']
})
print(agg_result)

# 窓関数の使用
df['出席率_ランク'] = df['出席率'].rank(method='dense', ascending=False)
print(df[['名前', '出席率', '出席率_ランク']].sort_values('出席率_ランク').head(10))
```

このコードでは、複雑な条件に基づくデータ選択、`melt()`関数を使用したデータのリシェイプ、複数の集計関数の同時適用、窓関数の使用など、高度なデータ操作の例を示しています。これらの機能を使いこなすことで、より柔軟で詳細なデータ分析が可能になります。

## 第13章: データの保存と読み込み

分析結果や中間データを保存し、後で再利用することは重要です。ここでは、Pandasを使用してデータを様々な形式で保存し、読み込む方法を学びます。

```python
# CSVファイルへの保存
df.to_csv('student_data.csv', index=False)

# Excelファイルへの保存
df.to_excel('student_data.xlsx', index=False)

# CSVファイルの読み込み
df_csv = pd.read_csv('student_data.csv')

# Excelファイルの読み込み
df_excel = pd.read_excel('student_data.xlsx')

# JSONファイルへの保存と読み込み
df.to_json('student_data.json', orient='records')
df_json = pd.read_json('student_data.json')

print("CSVから読み込んだデータ:")
print(df_csv.head())
print("\nExcelから読み込んだデータ:")
print(df_excel.head())
print("\nJSONから読み込んだデータ:")
print(df_json.head())
```

このコードでは、DataFrameをCSV、Excel、JSON形式で保存し、それぞれのファイルを読み込む方法を示しています。データの保存と読み込みは、データ分析のワークフローにおいて重要な役割を果たします。適切な形式でデータを保存することで、他のツールとの連携や後続の分析作業が容易になります。

## 第14章: パフォーマンスの最適化

大規模なデータセットを扱う際は、処理のパフォーマンスが重要になります。ここでは、NumPyとPandasを使用してパフォーマンスを最適化する方法を学びます。

```python
import time

# 大規模なデータセットの生成
large_df = pd.DataFrame({
    '名前': np.random.choice(['田中', '山田', '佐藤', '鈴木', '高橋'], 1000000),
    '年齢': np.random.randint(18, 60, 1000000),
    '成績': np.random.choice(['A', 'B', 'C', 'D'], 1000000),
    '出席率': np.random.uniform(0.5, 1.0, 1000000)
})

# 通常の方法での計算
start_time = time.time()
mean_age = large_df.groupby('名前')['年齢'].mean()
end_time = time.time()
print(f"通常の方法での実行時間: {end_time - start_time:.4f}秒")

# 最適化された方法での計算
start_time = time.time()
mean_age_optimized = large_df.groupby('名前')['年齢'].mean().compute()  # daskを使用した場合
end_time = time.time()
print(f"最適化された方法での実行時間: {end_time - start_time:.4f}秒")

# メモリ使用量の確認
print(f"データフレームのメモリ使用量: {large_df.memory_usage().sum() / 1e6:.2f} MB")

# カテゴリタイプの使用
large_df['名前'] = large_df['名前'].astype('category')
large_df['成績'] = large_df['成績'].astype('category')
print(f"カテゴリタイプ使用後のメモリ使用量: {large_df.memory_usage().sum() / 1e6:.2f} MB")
```

このコードでは、大規模なデータセットを生成し、通常の方法と最適化された方法（ここではdaskライブラリの使用を想定）での計算時間を比較しています。また、メモリ使用量を確認し、カテゴリタイプを使用してメモリ使用量を削減する方法も示しています。これらの最適化技術を使用することで、大規模なデータセットでも効率的に処理を行うことができます。

## 第15章: 機械学習との連携

NumPyとPandasは、機械学習のためのデータ準備に非常に有用です。ここでは、scikit-learnと連携して簡単な機械学習モデルを構築する方法を学びます。

```python
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# データの準備
X = df[['年齢', '出席率']]
y = df['成績']

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# データの標準化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# モデルの構築と学習
model = LogisticRegression(random_state=42)
model.fit(X_train_scaled, y_train)

# 予測と評価
y_pred = model.predict(X_test_scaled)
accuracy = accuracy_score(y_test, y_pred)
print(f"モデルの精度: {accuracy:.2f}")
print("\n分類レポート:")
print(classification_report(y_test, y_pred))

# 新しいデータでの予測
new_data = pd.DataFrame({'年齢': [22], '出席率': [0.85]})
new_data_scaled = scaler.transform(new_data)
prediction = model.predict(new_data_scaled)
print(f"\n新しいデータの予測結果: {prediction[0]}")
```

このコードでは、NumPyとPandasを使用してデータを準備し、scikit-learnを使用してロジスティック回帰モデルを構築しています。データの分割、標準化、モデルの学習と評価、新しいデータでの予測など、機械学習の基本的なワークフローを示しています。NumPyとPandasを使用することで、機械学習のためのデータ準備を効率的に行うことができます。

以上で、NumPyとPandasの基本から応用までを網羅した15章の記事が完成しました。これらの章を通じて、データ分析と機械学習の基礎を学ぶことができます。実際のプロジェクトでこれらの技術を活用し、さらに理解を深めていくことをお勧めします。