LESSON

データ操作

田中VPoE「Pandasの基本がわかったところで、もう少し実践的な操作を学ぼう。実際の分析では、フィルタリングやグループ化を駆使してデータを掘り下げていくんだ。」

あなた「Excelのピボットテーブルみたいなことができるんですか?」

田中VPoE「まさにそうだ。しかもPandasなら、コードで再現性のある操作ができる。NetShop社の購買データを使って練習してみよう。」

フィルタリング

条件によるフィルタリング

import pandas as pd

# 単一条件
high_value = df[df['amount'] > 10000]

# 複数条件(AND)
target = df[(df['amount'] > 10000) & (df['category'] == '家電')]

# 複数条件(OR)
target = df[(df['category'] == '家電') | (df['category'] == '書籍')]

# NOT条件
non_cancelled = df[~df['status'].isin(['cancelled', 'returned'])]

# isinで複数値
electronics = df[df['category'].isin(['家電', 'PC', 'スマホ'])]

# 文字列条件
tokyo_customers = df[df['address'].str.contains('東京')]

queryメソッド

条件が複雑な場合、queryメソッドが読みやすくなります:

# queryメソッド
result = df.query('amount > 10000 and category == "家電"')

# 変数を使う
min_amount = 10000
result = df.query('amount > @min_amount')

ソート

# 単一カラムでソート
df_sorted = df.sort_values('amount', ascending=False)

# 複数カラムでソート
df_sorted = df.sort_values(['category', 'amount'], ascending=[True, False])

# インデックスでソート
df_sorted = df.sort_index()

グループ化と集計

groupby

SQLのGROUP BYに相当する、データ分析で最も重要な操作の1つです。

# カテゴリ別の集計
category_stats = df.groupby('category')['amount'].agg([
    'count', 'sum', 'mean', 'median', 'std'
])

# 複数カラムでグループ化
monthly_category = df.groupby(['year_month', 'category'])['amount'].sum()

# 名前付き集計(推奨)
result = df.groupby('category').agg(
    order_count=('order_id', 'count'),
    total_revenue=('amount', 'sum'),
    avg_amount=('amount', 'mean'),
    unique_customers=('customer_id', 'nunique')
).reset_index()

集計関数一覧

関数説明用途
count非欠損値の数件数の集計
sum合計売上合計
mean平均平均客単価
median中央値外れ値に強い代表値
std標準偏差ばらつきの把握
min / max最小値 / 最大値範囲の確認
nuniqueユニーク数顧客数、商品数
first / last最初 / 最後の値時系列の端点

ピボットテーブル

Excelのピボットテーブルと同じ機能です:

# ピボットテーブル
pivot = df.pivot_table(
    values='amount',
    index='category',
    columns='month',
    aggfunc='sum',
    fill_value=0,
    margins=True  # 合計行・列を追加
)

クロス集計

# カテゴリと月のクロス集計(件数)
cross = pd.crosstab(df['category'], df['month'], margins=True)

ウィンドウ関数

時系列分析でよく使う移動計算:

# 7日移動平均
df['ma_7d'] = df['daily_sales'].rolling(window=7).mean()

# 累積合計
df['cumulative_sales'] = df['daily_sales'].cumsum()

# 前日比
df['daily_change'] = df['daily_sales'].pct_change()

# 前期の値
df['prev_month_sales'] = df['monthly_sales'].shift(1)

文字列操作

# 文字列メソッド(.str アクセサ)
df['name_upper'] = df['name'].str.upper()
df['first_name'] = df['name'].str.split(' ').str[0]
df['has_tokyo'] = df['address'].str.contains('東京')
df['email_domain'] = df['email'].str.split('@').str[1]

日付操作

# 日付型への変換
df['order_date'] = pd.to_datetime(df['order_date'])

# 日付要素の抽出
df['year'] = df['order_date'].dt.year
df['month'] = df['order_date'].dt.month
df['day_of_week'] = df['order_date'].dt.dayofweek  # 0=月曜
df['year_month'] = df['order_date'].dt.to_period('M')

# 日付でフィルタ
recent = df[df['order_date'] >= '2025-01-01']

# 日付差分
df['days_since_order'] = (pd.Timestamp.now() - df['order_date']).dt.days

apply関数

組み込み関数で対応できない複雑な変換には、applyを使います:

# Seriesに対するapply
df['amount_category'] = df['amount'].apply(
    lambda x: '高額' if x > 10000 else '中額' if x > 3000 else '少額'
)

# DataFrameの行に対するapply
def calc_discount_rate(row):
    if row['customer_rank'] == 'Gold':
        return row['amount'] * 0.1
    elif row['customer_rank'] == 'Silver':
        return row['amount'] * 0.05
    return 0

df['discount'] = df.apply(calc_discount_rate, axis=1)

注意:applyは便利ですが、大量データではベクトル化された操作より遅くなります。可能な限りPandasの組み込みメソッドやNumPyを使いましょう。

まとめ

項目ポイント
フィルタリング条件式、isin、queryで柔軟にデータを抽出
グループ化groupby + aggで集計。名前付き集計が推奨
ピボットテーブルpivot_tableで2次元の集計表を作成
ウィンドウ関数rolling, cumsum, pct_changeで時系列分析
日付操作dtアクセサで年月日・曜日を抽出

チェックリスト

  • 複数条件でデータをフィルタリングできる
  • groupbyで名前付き集計ができる
  • ピボットテーブルを作成できる
  • 日付型のデータから年月・曜日を抽出できる

次のステップへ

データ操作の基本テクニックを学びました。次は、実データで必ず直面する欠損値の処理方法を学びましょう。


推定読了時間:30分