Pandas入門:データ分析の基本操作完全ガイド

目次

Pandas入門:データ分析の基本操作完全ガイド

データ分析を始めるなら、Pandasは必須のライブラリです。この記事では、Pandasの基本的な使い方から実践的なデータ分析手法まで、初心者でもわかりやすく解説します。

Pandasとは?

Pandasの特徴

Pandas は、Pythonでデータ分析を行うための最も重要なライブラリの一つです。ExcelやSQLのような操作をPythonで簡単に実行できます。

主な機能

  • データ構造: Series(1次元)、DataFrame(2次元)
  • ファイルIO: CSV、Excel、JSON、SQL、Parquet対応
  • データ操作: フィルタリング、ソート、グループ化、結合
  • データクリーニング: 欠損値処理、重複削除、型変換
  • 統計分析: 基本統計、集計、ピボットテーブル
  • 時系列分析: 日付処理、リサンプリング、ローリング計算

環境構築とインストール

必要なライブラリのインストール

# 基本インストール
pip install pandas

# データ分析セット(推奨)
pip install pandas numpy matplotlib seaborn jupyter

# Excel対応
pip install openpyxl xlsxwriter

# 高速化
pip install fastparquet pyarrow

基本的なインポート

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta

# 表示設定
pd.set_option('display.max_columns', None)  # 全列表示
pd.set_option('display.max_rows', 100)     # 最大100行表示
pd.set_option('display.width', None)       # 幅制限なし
pd.set_option('display.float_format', '{:.2f}'.format)  # 小数点2桁

print("Pandas バージョン:", pd.__version__)

データ構造の基本:SeriesとDataFrame

Series:1次元データ

# Series の作成
import pandas as pd
import numpy as np

# リストから作成
prices = pd.Series([100, 150, 120, 180, 90])
print("価格データ:")
print(prices)
print()

# 辞書から作成
stock_prices = pd.Series({
    'Apple': 150.0,
    'Google': 2800.0,
    'Microsoft': 300.0,
    'Tesla': 800.0,
    'Amazon': 3200.0
})
print("株価データ:")
print(stock_prices)
print()

# インデックス付きで作成
dates = pd.date_range('2024-01-01', periods=5, freq='D')
daily_sales = pd.Series([1000, 1200, 950, 1100, 1300], index=dates)
print("日別売上:")
print(daily_sales)
print()

# Series の基本操作
print("基本統計:")
print(f"平均: {stock_prices.mean():.2f}")
print(f"最大値: {stock_prices.max():.2f}")
print(f"最小値: {stock_prices.min():.2f}")
print(f"標準偏差: {stock_prices.std():.2f}")

DataFrame:2次元データ

# DataFrame の作成方法

# 1. 辞書から作成
sales_data = {
    '商品名': ['商品A', '商品B', '商品C', '商品D', '商品E'],
    '価格': [1000, 1500, 800, 2000, 1200],
    '売上数': [100, 80, 150, 60, 120],
    'カテゴリ': ['電子機器', '衣料品', '食品', '電子機器', '衣料品']
}

df_sales = pd.DataFrame(sales_data)
print("売上データ:")
print(df_sales)
print()

# 2. NumPy配列から作成
np.random.seed(42)
data = np.random.randn(5, 4)
columns = ['A', 'B', 'C', 'D']
index = ['行1', '行2', '行3', '行4', '行5']

df_random = pd.DataFrame(data, columns=columns, index=index)
print("ランダムデータ:")
print(df_random)
print()

# DataFrame の基本情報
print("DataFrame の基本情報:")
print(f"形状: {df_sales.shape}")
print(f"列名: {list(df_sales.columns)}")
print(f"インデックス: {list(df_sales.index)}")
print(f"データ型:n{df_sales.dtypes}")

ファイルの読み込みと保存

CSV ファイルの操作

# サンプルデータの作成と保存
sample_data = {
    'date': pd.date_range('2024-01-01', periods=100, freq='D'),
    'product': np.random.choice(['商品A', '商品B', '商品C'], 100),
    'sales': np.random.randint(50, 200, 100),
    'price': np.random.uniform(1000, 5000, 100),
    'region': np.random.choice(['東京', '大阪', '名古屋'], 100)
}

df_sample = pd.DataFrame(sample_data)

# CSV に保存
df_sample.to_csv('sample_sales.csv', index=False, encoding='utf-8-sig')
print("サンプルデータを sample_sales.csv に保存しました")

# CSV から読み込み
df_loaded = pd.read_csv('sample_sales.csv', encoding='utf-8-sig')
print("CSV から読み込んだデータ:")
print(df_loaded.head())
print()

# 読み込み時のオプション
df_advanced = pd.read_csv(
    'sample_sales.csv',
    encoding='utf-8-sig',
    parse_dates=['date'],          # 日付列を自動変換
    index_col='date',              # 日付列をインデックスに
    dtype={'sales': 'int32'},      # データ型を指定
    nrows=10                       # 最初の10行のみ読み込み
)
print("高度な読み込み:")
print(df_advanced.head())

Excel ファイルの操作

# Excel ファイルへの保存と読み込み

# 複数シートでの保存
with pd.ExcelWriter('sales_analysis.xlsx', engine='openpyxl') as writer:
    # 元データ
    df_sample.to_excel(writer, sheet_name='生データ', index=False)

    # 商品別集計
    product_summary = df_sample.groupby('product').agg({
        'sales': ['sum', 'mean', 'count'],
        'price': 'mean'
    }).round(2)
    product_summary.to_excel(writer, sheet_name='商品別集計')

    # 地域別集計
    region_summary = df_sample.groupby('region').agg({
        'sales': 'sum',
        'price': 'mean'
    }).round(2)
    region_summary.to_excel(writer, sheet_name='地域別集計')

print("Excel ファイル 'sales_analysis.xlsx' を作成しました")

# Excel から読み込み
try:
    df_from_excel = pd.read_excel('sales_analysis.xlsx', sheet_name='生データ')
    print("Excel から読み込み成功")
    print(df_from_excel.head())
except FileNotFoundError:
    print("Excel ファイルが見つかりません")

データの探索と概要把握

基本的なデータ探索

# データの基本情報を確認
print("データの形状:", df_sample.shape)
print("列の情報:")
print(df_sample.info())
print()

print("基本統計量:")
print(df_sample.describe())
print()

print("最初の5行:")
print(df_sample.head())
print()

print("最後の5行:")
print(df_sample.tail())
print()

print("ランダムサンプル:")
print(df_sample.sample(5))
print()

# 欠損値の確認
print("欠損値の確認:")
print(df_sample.isnull().sum())
print()

# ユニーク値の確認
print("各列のユニーク値数:")
for col in df_sample.columns:
    print(f"{col}: {df_sample[col].nunique()}")

データ選択とフィルタリング

列の選択

# 列の選択方法

# 単一列の選択(Series として返される)
product_series = df_sample['product']
print("商品列(Series):")
print(product_series.head())
print(f"型: {type(product_series)}")
print()

# 複数列の選択
selected_cols = df_sample[['product', 'sales', 'price']]
print("複数列選択:")
print(selected_cols.head())
print()

# 数値列のみ選択
numeric_cols = df_sample.select_dtypes(include=[np.number])
print("数値列のみ:")
print(numeric_cols.head())

行の選択とフィルタリング

# 行の選択方法

# インデックスによる選択
print("最初の3行:")
print(df_sample.iloc[:3])
print()

# 条件によるフィルタリング
# 売上が100以上の行
high_sales = df_sample[df_sample['sales'] >= 100]
print(f"売上100以上: {len(high_sales)} 行")
print(high_sales.head())
print()

# 複数条件
tokyo_high_sales = df_sample[
    (df_sample['region'] == '東京') & 
    (df_sample['sales'] >= 100)
]
print(f"東京かつ売上100以上: {len(tokyo_high_sales)} 行")
print(tokyo_high_sales.head())
print()

# query() メソッドの使用
query_result = df_sample.query('sales > 100 and region == "東京"')
print("query() の結果:")
print(query_result.head())
print()

# 上位/下位N件の取得
top_sales = df_sample.nlargest(5, 'sales')
print("売上トップ5:")
print(top_sales)

データクリーニング

欠損値の処理

# 欠損値を含むサンプルデータの作成
df_missing = df_sample.copy()
# 意図的に欠損値を作成
np.random.seed(42)
missing_indices = np.random.choice(df_missing.index, size=20, replace=False)
df_missing.loc[missing_indices, 'sales'] = np.nan

print("欠損値の確認:")
print(df_missing.isnull().sum())
print()

# 欠損値の処理方法

# 1. 欠損値のある行を削除
df_dropped = df_missing.dropna()
print(f"欠損値削除後: {len(df_dropped)} 行")

# 2. 欠損値を平均値で埋める
df_filled_mean = df_missing.copy()
df_filled_mean['sales'] = df_filled_mean['sales'].fillna(df_filled_mean['sales'].mean())
print("平均値で補完後の欠損値:")
print(df_filled_mean.isnull().sum())

# 3. 前の値で埋める(時系列データ)
df_ffill = df_missing.sort_values('date').fillna(method='ffill')
print("前方埋めの欠損値:")
print(df_ffill.isnull().sum())

# 4. 線形補間
df_interpolated = df_missing.copy()
df_interpolated['sales'] = df_interpolated['sales'].interpolate()
print("線形補間後の欠損値:")
print(df_interpolated.isnull().sum())

重複データの処理

# 重複データを含むサンプルの作成
df_with_duplicates = pd.concat([df_sample, df_sample.sample(10)], ignore_index=True)
print(f"重複を含むデータ: {len(df_with_duplicates)} 行")
print(f"重複行数: {df_with_duplicates.duplicated().sum()}")

# 重複の削除
df_no_duplicates = df_with_duplicates.drop_duplicates()
print(f"重複削除後: {len(df_no_duplicates)} 行")

# 特定列での重複削除
df_unique_products = df_with_duplicates.drop_duplicates(subset=['product', 'date'])
print(f"商品・日付の組み合わせで重複削除: {len(df_unique_products)} 行")

データの集計と統計

基本的な統計量

# 基本統計量の計算

print("数値データの基本統計:")
print(df_sample[['sales', 'price']].describe())
print()

# 個別統計量
print("個別統計量:")
print(f"売上の平均: {df_sample['sales'].mean():.2f}")
print(f"売上の中央値: {df_sample['sales'].median():.2f}")
print(f"売上の標準偏差: {df_sample['sales'].std():.2f}")
print(f"売上の分散: {df_sample['sales'].var():.2f}")
print()

# 相関係数
correlation = df_sample[['sales', 'price']].corr()
print("相関係数:")
print(correlation)

groupby による集計

# groupby による集計分析

# 1. 商品別集計
product_stats = df_sample.groupby('product').agg({
    'sales': ['count', 'sum', 'mean', 'std'],
    'price': ['mean', 'min', 'max']
}).round(2)

print("商品別統計:")
print(product_stats)
print()

# 2. 地域別集計
region_stats = df_sample.groupby('region').agg({
    'sales': ['sum', 'mean'],
    'price': 'mean'
}).round(2)

print("地域別統計:")
print(region_stats)
print()

# 3. 複数列でのグループ化
multi_group = df_sample.groupby(['region', 'product']).agg({
    'sales': 'sum',
    'price': 'mean'
}).round(2)

print("地域×商品別統計:")
print(multi_group)

ピボットテーブル

# ピボットテーブルの作成

# 基本的なピボットテーブル
pivot_basic = df_sample.pivot_table(
    values='sales',
    index='region',
    columns='product',
    aggfunc='sum',
    fill_value=0
)

print("基本ピボットテーブル(地域×商品の売上合計):")
print(pivot_basic)
print()

# 複数の値を持つピボットテーブル
pivot_multi = df_sample.pivot_table(
    values=['sales', 'price'],
    index='region',
    columns='product',
    aggfunc={'sales': 'sum', 'price': 'mean'},
    fill_value=0
)

print("複数値ピボットテーブル:")
print(pivot_multi.round(2))
print()

# 集計機能付きピボットテーブル
pivot_with_totals = df_sample.pivot_table(
    values='sales',
    index='region',
    columns='product',
    aggfunc='sum',
    fill_value=0,
    margins=True,  # 合計行・列を追加
    margins_name='総計'
)

print("合計付きピボットテーブル:")
print(pivot_with_totals)

時系列データの処理

日付データの操作

# 時系列データの処理

# 日付インデックスの設定
df_timeseries = df_sample.copy()
df_timeseries['date'] = pd.to_datetime(df_timeseries['date'])
df_timeseries = df_timeseries.set_index('date')

print("時系列データ:")
print(df_timeseries.head())
print()

# 日付コンポーネントの抽出
df_timeseries['year'] = df_timeseries.index.year
df_timeseries['month'] = df_timeseries.index.month
df_timeseries['day'] = df_timeseries.index.day
df_timeseries['weekday'] = df_timeseries.index.day_name()

print("日付コンポーネント:")
print(df_timeseries[['year', 'month', 'day', 'weekday']].head())
print()

# 期間での絞り込み
january_data = df_timeseries['2024-01']
print(f"1月のデータ: {len(january_data)} 行")

リサンプリングと集計

# リサンプリング(時間単位の変更)

# 日次データを週次に集計
weekly_sales = df_timeseries.resample('W')['sales'].agg(['sum', 'mean', 'count'])
print("週次集計:")
print(weekly_sales.head())
print()

# 月次集計
monthly_stats = df_timeseries.resample('M').agg({
    'sales': ['sum', 'mean', 'count'],
    'price': 'mean'
}).round(2)

print("月次統計:")
print(monthly_stats)

移動平均とローリング計算

# ローリング計算

# 移動平均
df_timeseries['sales_ma7'] = df_timeseries['sales'].rolling(window=7).mean()
df_timeseries['sales_ma30'] = df_timeseries['sales'].rolling(window=30).mean()

print("移動平均:")
print(df_timeseries[['sales', 'sales_ma7', 'sales_ma30']].head(10))
print()

# その他のローリング統計
df_timeseries['sales_rolling_std'] = df_timeseries['sales'].rolling(window=7).std()
df_timeseries['sales_rolling_max'] = df_timeseries['sales'].rolling(window=7).max()

print("ローリング統計:")
print(df_timeseries[['sales', 'sales_rolling_std', 'sales_rolling_max']].head(10))

実践的なデータ分析例

売上データ分析システム

class SalesAnalyzer:
    """売上データ分析システム"""

    def __init__(self, df):
        self.df = df.copy()
        self.prepare_data()

    def prepare_data(self):
        """データの前処理"""
        # 日付変換
        if 'date' in self.df.columns:
            self.df['date'] = pd.to_datetime(self.df['date'])

        # 売上金額を計算
        if 'sales' in self.df.columns and 'price' in self.df.columns:
            self.df['revenue'] = self.df['sales'] * self.df['price']

        # 日付コンポーネントの追加
        if 'date' in self.df.columns:
            self.df['year'] = self.df['date'].dt.year
            self.df['month'] = self.df['date'].dt.month
            self.df['weekday'] = self.df['date'].dt.day_name()

    def summary_report(self):
        """サマリーレポート生成"""
        report = {}

        # 基本統計
        report['基本統計'] = {
            '総売上': self.df['revenue'].sum(),
            '平均売上': self.df['revenue'].mean(),
            '売上件数': len(self.df),
            '期間': f"{self.df['date'].min().date()} ~ {self.df['date'].max().date()}"
        }

        # 商品別分析
        product_analysis = self.df.groupby('product').agg({
            'sales': 'sum',
            'revenue': 'sum',
            'price': 'mean'
        }).round(2)

        product_analysis['revenue_share'] = (
            product_analysis['revenue'] / product_analysis['revenue'].sum() * 100
        ).round(2)

        report['商品別分析'] = product_analysis.sort_values('revenue', ascending=False)

        # 地域別分析
        region_analysis = self.df.groupby('region').agg({
            'sales': 'sum',
            'revenue': 'sum'
        }).round(2)

        region_analysis['revenue_share'] = (
            region_analysis['revenue'] / region_analysis['revenue'].sum() * 100
        ).round(2)

        report['地域別分析'] = region_analysis.sort_values('revenue', ascending=False)

        return report

    def generate_insights(self):
        """洞察の生成"""
        insights = []

        # 売上トップ商品
        top_product = self.df.groupby('product')['revenue'].sum().idxmax()
        insights.append(f"最も売上の高い商品: {top_product}")

        # 売上トップ地域
        top_region = self.df.groupby('region')['revenue'].sum().idxmax()
        insights.append(f"最も売上の高い地域: {top_region}")

        # 曜日別の傾向
        weekday_sales = self.df.groupby('weekday')['revenue'].mean()
        best_weekday = weekday_sales.idxmax()
        insights.append(f"最も売上の良い曜日: {best_weekday}")

        # 価格と売上の関係
        correlation = self.df['price'].corr(self.df['sales'])
        if correlation > 0.3:
            insights.append("価格と売上に正の相関があります(高価格商品ほど良く売れる)")
        elif correlation < -0.3:
            insights.append("価格と売上に負の相関があります(低価格商品ほど良く売れる)")
        else:
            insights.append("価格と売上の相関は弱いです")

        return insights

# 分析の実行
analyzer = SalesAnalyzer(df_sample)

print("=" * 60)
print("売上分析レポート")
print("=" * 60)

report = analyzer.summary_report()

print("n【基本統計】")
for key, value in report['基本統計'].items():
    if isinstance(value, (int, float)):
        print(f"{key}: {value:,.0f}")
    else:
        print(f"{key}: {value}")

print("n【商品別分析】")
print(report['商品別分析'])

print("n【地域別分析】")
print(report['地域別分析'])

print("n【主要な洞察】")
insights = analyzer.generate_insights()
for i, insight in enumerate(insights, 1):
    print(f"{i}. {insight}")

重要なクラス・メソッドリファレンス

pandas.DataFrame クラス

データ分析の中核となるDataFrameの主要メソッドをカテゴリ別に整理しました。

import pandas as pd
import numpy as np

# DataFrame作成・情報取得
df_methods_info = {
    # 基本情報
    "df.shape": "行数・列数の取得 (行, 列)",
    "df.info()": "データ型・メモリ使用量・欠損値情報",
    "df.describe()": "数値列の基本統計量(平均・標準偏差等)",
    "df.head(n)": "先頭n行を表示(デフォルト5行)",
    "df.tail(n)": "末尾n行を表示(デフォルト5行)",
    "df.sample(n)": "ランダムにn行をサンプリング",

    # 列・インデックス情報
    "df.columns": "列名一覧を取得",
    "df.index": "インデックス一覧を取得",
    "df.dtypes": "各列のデータ型を取得",
    "df.memory_usage()": "メモリ使用量を詳細表示"
}

print("DataFrame基本情報取得メソッド:")
for method, description in df_methods_info.items():
    print(f"  {method:<25} # {description}")

データ選択・フィルタリング

# データ選択メソッド
selection_methods = {
    # 列選択
    "df['列名']": "単一列選択(Seriesとして返却)",
    "df[['列1', '列2']]": "複数列選択(DataFrameとして返却)",
    "df.select_dtypes(include=['number'])": "データ型による列選択",
    "df.filter(regex='^売上')": "正規表現による列名マッチング",

    # 行選択
    "df.iloc[0:5, 1:3]": "位置ベース選択(行・列のインデックス番号)",
    "df.loc['2024-01':'2024-12', '売上']": "ラベルベース選択(行・列名指定)",
    "df.at[0, '列名']": "単一セルの高速アクセス",
    "df.iat[0, 1]": "位置ベース単一セルアクセス",

    # 条件フィルタリング
    "df[df['売上'] > 1000]": "単一条件フィルタリング",
    "df[(df['売上'] > 1000) & (df['地域'] == '東京')]": "複数条件フィルタリング(AND)",
    "df.query('売上 > 1000 and 地域 == "東京"')": "SQL風条件指定",
    "df.nlargest(5, '売上')": "指定列の上位n件取得",
    "df.nsmallest(5, '売上')": "指定列の下位n件取得"
}

print("nデータ選択・フィルタリングメソッド:")
for method, description in selection_methods.items():
    print(f"  {method:<45} # {description}")

データ操作・変換

# データ操作メソッド
operation_methods = {
    # 行・列操作
    "df.drop(columns=['列名'])": "列の削除",
    "df.drop(index=[0, 1])": "行の削除(インデックス指定)",
    "df.rename(columns={'旧名': '新名'})": "列名変更",
    "df.reset_index(drop=True)": "インデックスリセット",
    "df.set_index('列名')": "指定列をインデックスに設定",

    # データ変換
    "df.astype({'列名': 'int32'})": "データ型変換",
    "df.replace({'旧値': '新値'})": "値の置換",
    "df.map({'A': 1, 'B': 2})": "Series値のマッピング変換",
    "df.apply(lambda x: x*2)": "関数適用(列単位)",
    "df.applymap(lambda x: str(x).upper())": "全要素に関数適用",

    # 新列作成
    "df.assign(新列=df['A'] + df['B'])": "新列追加(メソッドチェーン対応)",
    "df.eval('新列 = A + B')": "式評価による新列作成(高速)"
}

print("nデータ操作・変換メソッド:")
for method, description in operation_methods.items():
    print(f"  {method:<40} # {description}")

データクリーニング

# データクリーニングメソッド
cleaning_methods = {
    # 欠損値処理
    "df.isnull()": "欠損値の検出(True/False)",
    "df.isnull().sum()": "列ごとの欠損値数カウント",
    "df.dropna()": "欠損値を含む行を削除",
    "df.dropna(subset=['列名'])": "指定列の欠損値がある行を削除",
    "df.fillna(value)": "欠損値を指定値で埋める",
    "df.fillna(method='ffill')": "前の値で欠損値を埋める",
    "df.fillna(method='bfill')": "後の値で欠損値を埋める",
    "df.interpolate()": "線形補間で欠損値を埋める",

    # 重複処理
    "df.duplicated()": "重複行の検出",
    "df.drop_duplicates()": "重複行の削除",
    "df.drop_duplicates(subset=['列名'])": "指定列での重複削除",

    # 異常値処理
    "df.clip(lower=0, upper=100)": "値の範囲制限",
    "df[df['列名'].between(10, 90)]": "範囲内データの抽出"
}

print("nデータクリーニングメソッド:")
for method, description in cleaning_methods.items():
    print(f"  {method:<35} # {description}")

集計・統計分析

# 集計・統計メソッド
aggregation_methods = {
    # 基本統計
    "df.mean()": "平均値計算",
    "df.median()": "中央値計算", 
    "df.mode()": "最頻値計算",
    "df.std()": "標準偏差計算",
    "df.var()": "分散計算",
    "df.min() / df.max()": "最小値・最大値",
    "df.sum()": "合計値計算",
    "df.count()": "非欠損値数カウント",
    "df.quantile([0.25, 0.5, 0.75])": "パーセンタイル計算",

    # 相関・共分散
    "df.corr()": "相関係数行列計算",
    "df.cov()": "共分散行列計算",
    "df.corrwith(other_series)": "他のSeriesとの相関",

    # GroupBy集計
    "df.groupby('列名').agg({'列名': ['sum', 'mean']})": "グループ別複数統計量",
    "df.groupby('列名').transform('mean')": "グループ統計量を元サイズで返却",
    "df.groupby('列名').apply(custom_function)": "グループ別カスタム関数適用",

    # ピボットテーブル
    "df.pivot_table(values, index, columns, aggfunc)": "ピボットテーブル作成",
    "df.crosstab(df['列1'], df['列2'])": "クロス集計表作成"
}

print("n集計・統計分析メソッド:")
for method, description in aggregation_methods.items():
    print(f"  {method:<50} # {description}")

ファイルI/O操作

# ファイル入出力メソッド
io_methods = {
    # 読み込み
    "pd.read_csv('file.csv', encoding='utf-8-sig')": "CSV読み込み(日本語対応)",
    "pd.read_excel('file.xlsx', sheet_name=None)": "Excel読み込み(全シート)",
    "pd.read_json('file.json')": "JSON読み込み",
    "pd.read_sql(sql, connection)": "SQLデータベース読み込み",
    "pd.read_parquet('file.parquet')": "Parquet読み込み(高速)",

    # 保存
    "df.to_csv('output.csv', index=False, encoding='utf-8-sig')": "CSV保存",
    "df.to_excel('output.xlsx', sheet_name='シート1', index=False)": "Excel保存",
    "df.to_json('output.json', orient='records')": "JSON保存",
    "df.to_sql('table_name', connection, if_exists='replace')": "SQLデータベース保存",
    "df.to_parquet('output.parquet')": "Parquet保存(高速)",

    # 読み込みオプション
    "pd.read_csv(usecols=['列1', '列2'])": "必要列のみ読み込み",
    "pd.read_csv(dtype={'列名': 'category'})": "データ型指定読み込み",
    "pd.read_csv(parse_dates=['日付列'])": "日付列自動変換",
    "pd.read_csv(chunksize=10000)": "大容量ファイルの分割読み込み"
}

print("nファイルI/O操作メソッド:")
for method, description in io_methods.items():
    print(f"  {method:<55} # {description}")

時系列データ処理

# 時系列処理メソッド
timeseries_methods = {
    # 日付変換・操作
    "pd.to_datetime(df['日付列'])": "文字列を日付型に変換",
    "pd.date_range('2024-01-01', periods=365, freq='D')": "日付範囲生成",
    "df.set_index('date')": "日付列をインデックスに設定",
    "df.index.year / .month / .day": "日付コンポーネント抽出",
    "df.index.dayofweek": "曜日番号取得(月曜=0)",
    "df.index.day_name()": "曜日名取得",

    # 期間選択
    "df['2024']": "年での絞り込み",
    "df['2024-01']": "年月での絞り込み", 
    "df['2024-01-01':'2024-12-31']": "期間範囲での絞り込み",

    # リサンプリング
    "df.resample('M').sum()": "月次集計",
    "df.resample('W').mean()": "週次平均",
    "df.resample('Q').agg({'列名': ['sum', 'mean']})": "四半期集計",

    # ローリング計算
    "df.rolling(window=7).mean()": "7日移動平均",
    "df.rolling(window=30).std()": "30日移動標準偏差",
    "df.expanding().sum()": "累積合計",
    "df.ewm(span=10).mean()": "指数加重移動平均"
}

print("n時系列データ処理メソッド:")
for method, description in timeseries_methods.items():
    print(f"  {method:<50} # {description}")

データ結合・マージ

# データ結合メソッド
merge_methods = {
    # DataFrame結合
    "pd.concat([df1, df2], axis=0)": "縦方向結合(行の追加)",
    "pd.concat([df1, df2], axis=1)": "横方向結合(列の追加)",
    "pd.concat([df1, df2], ignore_index=True)": "インデックスリセット結合",

    # SQL風結合
    "pd.merge(df1, df2, on='共通列')": "内部結合(INNER JOIN)",
    "pd.merge(df1, df2, how='left', on='列名')": "左外部結合(LEFT JOIN)",
    "pd.merge(df1, df2, how='right', on='列名')": "右外部結合(RIGHT JOIN)",
    "pd.merge(df1, df2, how='outer', on='列名')": "完全外部結合(FULL OUTER JOIN)",
    "pd.merge(df1, df2, left_on='列1', right_on='列2')": "異なる列名での結合",

    # インデックス結合
    "df1.join(df2, how='left')": "インデックスベース結合",
    "df1.join(df2, lsuffix='_left', rsuffix='_right')": "同名列の接尾辞指定"
}

print("nデータ結合・マージメソッド:")
for method, description in merge_methods.items():
    print(f"  {method:<50} # {description}")

パフォーマンス最適化のコツ

# パフォーマンス最適化
performance_tips = {
    # メモリ最適化
    "df.astype('category')": "カテゴリ型でメモリ削減",
    "df.astype('int32')": "小さい整数型でメモリ削減",
    "pd.read_csv(dtype={'列名': 'category'})": "読み込み時型指定",

    # 高速化テクニック  
    "df.eval('新列 = A + B')": "数値演算の高速化",
    "df.query('A > 100')": "フィルタリングの高速化",
    "df.loc[mask, '列名'] = value": "条件付き代入の高速化",
    "df.values": "NumPy配列として取得(計算高速化)",

    # ベクトル化操作
    "df['列名'].map(辞書)": "マッピング変換(高速)",
    "df['列名'].str.contains('パターン')": "文字列操作のベクトル化",
    "df['列名'].dt.year": "日付操作のベクトル化",

    # チャンクサイズ処理
    "for chunk in pd.read_csv(chunksize=10000)": "大容量ファイルの分割処理"
}

print("nパフォーマンス最適化のコツ:")
for method, description in performance_tips.items():
    print(f"  {method:<45} # {description}")

実践的な使用パターン

class PandasBestPractices:
    """Pandas使用のベストプラクティス集"""

    @staticmethod
    def efficient_data_loading(file_path):
        """効率的なデータ読み込み"""
        # 必要列のみ、適切な型で読み込み
        df = pd.read_csv(
            file_path,
            usecols=['日付', '商品', '売上', '地域'],  # 必要列のみ
            dtype={
                '商品': 'category',      # カテゴリ型でメモリ削減
                '地域': 'category',
                '売上': 'float32'        # 精度と速度のバランス
            },
            parse_dates=['日付'],        # 日付自動変換
            encoding='utf-8-sig'
        )
        return df

    @staticmethod  
    def method_chaining_example(df):
        """メソッドチェーンの活用例"""
        result = (df
                 .dropna(subset=['売上'])           # 欠損値除去
                 .query('売上 > 0')                 # 正の売上のみ
                 .assign(売上カテゴリ=lambda x: pd.cut(x['売上'], 
                                                  bins=[0, 1000, 5000, float('inf')],
                                                  labels=['低', '中', '高']))
                 .groupby(['地域', '売上カテゴリ'])   # グループ化
                 .agg({'売上': ['sum', 'count']})   # 集計
                 .round(2))                        # 小数点処理
        return result

    @staticmethod
    def memory_optimization(df):
        """メモリ使用量最適化"""
        # 数値列の最適化
        for col in df.select_dtypes(include=['int64']).columns:
            if df[col].min() >= 0 and df[col].max() <= 255:
                df[col] = df[col].astype('uint8')
            elif df[col].min() >= -128 and df[col].max() <= 127:
                df[col] = df[col].astype('int8')

        # 文字列列のカテゴリ化
        for col in df.select_dtypes(include=['object']).columns:
            if df[col].nunique() / len(df) < 0.5:  # ユニーク率50%未満
                df[col] = df[col].astype('category')

        return df

# 使用例
print("n実践的な使用パターン:")
print("1. efficient_data_loading() - 効率的なデータ読み込み")
print("2. method_chaining_example() - メソッドチェーンの活用")
print("3. memory_optimization() - メモリ使用量最適化")

まとめとベストプラクティス

Pandas使用時のベストプラクティス

データ読み込み:

  • 必要な列のみ読み込む(usecols パラメータ)
  • 適切なデータ型を指定(dtype パラメータ)
  • 大きなファイルはchunksizeで分割読み込み

メモリ管理:

  • 不要なデータフレームは del で削除
  • カテゴリ型を積極的に使用
  • float64 より float32 を検討

操作の効率化:

  • ループを避けてベクトル化操作を使用
  • 複数の条件は query() で読みやすく
  • chain method で可読性向上

データ品質:

  • 定期的な欠損値チェック
  • 重複データの確認と処理
  • データ型の一貫性確保

次のステップ

  1. 高度な分析手法: 機械学習ライブラリとの連携
  2. ビッグデータ処理: Dask、Polarsなどの活用
  3. データベース連携: SQLAlchemyとの組み合わせ
  4. 可視化の強化: Plotly、Bokehなどの活用

関連記事

Pandasをマスターすることで、データ分析の世界が大きく広がります。まずは基本操作から始めて、徐々に高度な機能を身につけていきましょう。実際のプロジェクトで使いながら覚えることが、上達への近道です。


データ分析を深める