dotConf, Inc
📊

データサイエンスに必要なPythonライブラリまとめ

はじめに

はじめまして、
株式会社dotConfにて、AIエンジニアをしている古菅です。

前回は「DockerでJupyter環境を構築する方法」を紹介しましたが、今回はデータサイエンスの実務で必要となるPythonライブラリを体系的にまとめました。基本的な使い方だけでなく、パフォーマンス最適化や実践的なテクニックも含めて解説します。

1. データ加工・前処理

NumPy:高速数値計算の基盤

NumPyはPythonで数値計算を行うための基本ライブラリです。リストよりも10〜100倍高速で、大量のデータを効率的に処理できます。

基本的な使い方

import numpy as np

# 配列の作成
arr = np.array([1, 2, 3, 4, 5])
print(arr)  # [1 2 3 4 5]

# 便利な配列生成
zeros = np.zeros(5)        # [0. 0. 0. 0. 0.]
ones = np.ones(3)          # [1. 1. 1.]
range_arr = np.arange(0, 10, 2)  # [0 2 4 6 8]

# 基本的な計算
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a + b)    # [5 7 9] - 要素ごとに足し算
print(a * 2)    # [2 4 6] - すべての要素を2倍

# 統計関数
data = np.array([10, 20, 30, 40, 50])
print(np.mean(data))   # 30.0 - 平均
print(np.std(data))    # 14.14... - 標準偏差
print(np.max(data))    # 50 - 最大値

2次元配列(行列)の操作

# 2次元配列の作成
matrix = np.array([[1, 2, 3], 
                   [4, 5, 6]])
print(matrix.shape)  # (2, 3) - 2行3列

# 行と列の計算
# axis=0は「縦方向(列ごと)」、axis=1は「横方向(行ごと)」
col_means = matrix.mean(axis=0)  # [2.5 3.5 4.5] - 各列の平均
row_sums = matrix.sum(axis=1)    # [6 15] - 各行の合計

条件に基づくデータ抽出

# 条件を満たす要素だけ取り出す
arr = np.array([1, 5, 3, 8, 2, 7])
positive = arr[arr > 5]  # [8 7] - 5より大きい要素だけ
print(positive)

よく使うポイント

  • NumPyは配列全体に対して一度に計算できるので高速
  • dtype='float32'を指定するとメモリ使用量を半分にできる
  • ループを書く代わりに、配列演算を使うのがコツ

pandas:データ分析の中核

pandasは、Excelのようにテーブル形式のデータをPythonで扱えるようにするライブラリです。CSVファイルの読み込みやデータの集計が簡単にできます。

基本的なデータの読み込みと確認

import pandas as pd

# CSVファイルを読み込む
df = pd.read_csv('data.csv')

# データの最初の5行を表示
print(df.head())

# データの情報を確認
print(df.info())     # 列名、データ型、欠損値の有無
print(df.describe()) # 数値列の統計情報(平均、最大値など)

データの抽出と加工

# 特定の列を取り出す
ages = df['age']

# 条件に合うデータを抽出
young_people = df[df['age'] < 30]
high_earners = df[df['salary'] > 50000]

# 複数条件の組み合わせ
result = df[(df['age'] > 20) & (df['salary'] < 100000)]

# 新しい列を追加
df['bonus'] = df['salary'] * 0.1
df['tax'] = df['salary'] * 0.2

データの集計

# グループごとに集計
# 部署ごとの平均給与を計算
dept_avg = df.groupby('department')['salary'].mean()
print(dept_avg)

# 複数の集計を同時に実行
summary = df.groupby('department').agg({
    'salary': ['mean', 'max', 'count'],
    'age': 'mean'
})
print(summary)

欠損値の処理

# 欠損値を確認
print(df.isnull().sum())  # 各列の欠損値の数

# 欠損値を含む行を削除
df_cleaned = df.dropna()

# 欠損値を特定の値で埋める
df['salary'].fillna(0, inplace=True)      # 0で埋める
df['age'].fillna(df['age'].mean(), inplace=True)  # 平均値で埋める

データの結合

# 2つのデータフレームを結合
df1 = pd.DataFrame({'id': [1, 2, 3], 'name': ['Alice', 'Bob', 'Charlie']})
df2 = pd.DataFrame({'id': [1, 2, 3], 'salary': [50000, 60000, 70000]})

# idをキーにして結合
merged = pd.merge(df1, df2, on='id')
print(merged)

メモリ効率化のテクニック

# 大きなファイルを効率的に読み込む
df = pd.read_csv('large_file.csv',
                 usecols=['col1', 'col2', 'col3'],  # 必要な列だけ読み込む
                 dtype={'col1': 'category'})  # カテゴリ型でメモリ節約

# カテゴリ型への変換(メモリを大幅削減)
# 繰り返しの多いデータ(性別、地域名など)に有効
df['status'] = df['status'].astype('category')

# チャンク処理:メモリに載らない大きなファイルを分割処理
for chunk in pd.read_csv('huge_file.csv', chunksize=10000):
    # 1万行ずつ処理
    process_data(chunk)

よく使うポイント

  • head()でデータの最初の数行を確認する習慣をつける
  • info()でデータ型と欠損値を確認
  • グループ化と集計はgroupby()agg()の組み合わせ
  • メモリが足りない時はchunksizeで分割処理

2. データ可視化

Matplotlib/Seaborn:静的グラフの作成

Matplotlibはオブジェクト指向APIとpyplot APIの2つのインターフェースを提供しますが、再現性と柔軟性の観点からオブジェクト指向APIの使用を推奨します。GridSpecを使うことで、複雑なレイアウトを正確に制御できます。

import matplotlib.pyplot as plt
import seaborn as sns

# GridSpecによる柔軟なサブプロット配置
fig = plt.figure(figsize=(15, 10))
gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
ax1 = fig.add_subplot(gs[0, :])  # 1行目全体
ax2 = fig.add_subplot(gs[1, :-1])  # 2行目の左2列
ax3 = fig.add_subplot(gs[1:, -1])  # 2-3行目の右端

# スタイル設定のカスタマイズ
plt.rcParams['font.size'] = 12
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['figure.dpi'] = 100

# Seabornによる統計的可視化
# jointplotは散布図と周辺分布を同時に表示
sns.jointplot(data=df, x='feature1', y='feature2', kind='hex', cmap='YlOrRd')

# FacetGridで複数の条件を一度に比較
sns.catplot(data=df, x='category', y='value', col='group', kind='box',
            height=4, aspect=1.5, palette='Set2')

# ヒートマップで相関係数を可視化
corr_matrix = df.select_dtypes(include=[np.number]).corr()
mask = np.triu(np.ones_like(corr_matrix, dtype=bool))  # 上三角を非表示
sns.heatmap(corr_matrix, mask=mask, annot=True, fmt='.2f', 
            cmap='coolwarm', center=0, vmin=-1, vmax=1)

パフォーマンスTips

  • 大量のデータ点を描画する際はrasterized=Trueでベクトル形式からラスタ形式に変換
  • plt.ioff()で対話モードをオフにし、メモリ使用量を削減
  • fig.savefig()ではbbox_inches='tight'で余白を最適化

Plotly:インタラクティブ可視化

Plotlyは宣言的なAPIを持ち、WebGLレンダリングにより大規模データでも滑らかな操作を実現します。ダッシュボードやレポートの埋め込みに適しています。

import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots

# 複数のトレースを持つインタラクティブグラフ
fig = go.Figure()
fig.add_trace(go.Scatter(
    x=df['date'], y=df['value'], 
    mode='lines+markers',
    name='実績値',
    line=dict(color='royalblue', width=2),
    hovertemplate='日付: %{x}<br>値: %{y:.2f}<extra></extra>'
))

# 移動平均線を追加
fig.add_trace(go.Scatter(
    x=df['date'], 
    y=df['value'].rolling(7).mean(),
    mode='lines',
    name='7日移動平均',
    line=dict(color='orange', dash='dash')
))

fig.update_layout(
    xaxis_rangeslider_visible=True,  # 範囲選択スライダー
    hovermode='x unified',  # 統一されたホバー表示
    template='plotly_white',  # テーマ設定
    xaxis=dict(rangeslider=dict(visible=True)),
    yaxis=dict(fixedrange=False)  # Y軸のズーム有効化
)

# サブプロットで複数グラフを配置
fig = make_subplots(
    rows=2, cols=2,
    subplot_titles=('時系列', '散布図', '箱ひげ図', 'ヒストグラム'),
    specs=[[{'type': 'scatter'}, {'type': 'scatter'}],
           [{'type': 'box'}, {'type': 'histogram'}]]
)

使い分けの指針

  • 論文・レポート: Matplotlib/Seaborn(高解像度の静的画像)
  • データ探索: Plotly(インタラクティブな分析)
  • Webアプリケーション: Plotly Dash(リアルタイム更新)

3. 機械学習

scikit-learn:標準的な機械学習フレームワーク

scikit-learnは統一されたAPI設計(Estimator API)により、すべてのアルゴリズムがfit()predict()transform()の一貫したインターフェースを持ちます。Pipelineによる前処理とモデルの統合、交差検証、ハイパーパラメータチューニングを一元管理できます。

from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV, StratifiedKFold

# 前処理パイプラインの構築
numeric_features = ['age', 'income']
categorical_features = ['occupation', 'education']

# 数値特徴の前処理:欠損値補完→標準化
numeric_transformer = Pipeline([
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())
])

# カテゴリ特徴の前処理:欠損値補完→ワンホットエンコーディング
categorical_transformer = Pipeline([
    ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
    ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
])

# ColumnTransformerで列ごとに異なる前処理を適用
preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, numeric_features),
        ('cat', categorical_transformer, categorical_features)
    ],
    remainder='drop'  # 指定外の列は削除
)

# エンドツーエンドのパイプライン
pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('classifier', RandomForestClassifier(random_state=42))
])

# 層化K分割交差検証によるハイパーパラメータチューニング
param_grid = {
    'classifier__n_estimators': [100, 200, 300],
    'classifier__max_depth': [10, 20, None],
    'classifier__min_samples_split': [2, 5, 10],
    'classifier__class_weight': ['balanced', None]
}

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
grid_search = GridSearchCV(
    pipeline, 
    param_grid, 
    cv=cv, 
    scoring='f1_weighted',
    n_jobs=-1,
    verbose=1,
    return_train_score=True  # 過学習の検出に有用
)

grid_search.fit(X_train, y_train)

# 最適モデルの取得と評価
best_model = grid_search.best_estimator_
print(f"Best parameters: {grid_search.best_params_}")
print(f"Best CV score: {grid_search.best_score_:.4f}")

実践的なテクニック

  • make_column_transformer()で前処理を簡潔に記述
  • CalibratedClassifierCVで確率予測のキャリブレーション
  • learning_curve()で学習曲線を描画し過学習・未学習を診断
  • カスタムTransformerをBaseEstimatorTransformerMixinで実装
from sklearn.base import BaseEstimator, TransformerMixin

class OutlierRemover(BaseEstimator, TransformerMixin):
    def __init__(self, factor=1.5):
        self.factor = factor
    
    def fit(self, X, y=None):
        Q1 = np.percentile(X, 25, axis=0)
        Q3 = np.percentile(X, 75, axis=0)
        IQR = Q3 - Q1
        self.lower_bound = Q1 - self.factor * IQR
        self.upper_bound = Q3 + self.factor * IQR
        return self
    
    def transform(self, X):
        return np.clip(X, self.lower_bound, self.upper_bound)

モデル評価の高度な指標

from sklearn.metrics import classification_report, roc_auc_score, roc_curve
from sklearn.metrics import precision_recall_curve, average_precision_score

# 多クラス分類の詳細評価
print(classification_report(y_test, y_pred))

# ROC-AUCとPR-AUC(不均衡データではPR-AUCが有用)
roc_auc = roc_auc_score(y_test, y_proba, multi_class='ovr')
pr_auc = average_precision_score(y_test, y_proba)

XGBoost/LightGBM:勾配ブースティング

XGBoost/LightGBMは、機械学習の中でも特に高精度な予測ができるアルゴリズムです。Kaggleなどのデータ分析コンペティションで頻繁に優勝するほど強力で、実務でも広く使われています。

import lightgbm as lgb

# LightGBMの高度な設定
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)

params = {
    'objective': 'binary',
    'metric': 'auc',
    'boosting_type': 'gbdt',
    'num_leaves': 31,
    'learning_rate': 0.05,
    'feature_fraction': 0.9,
    'bagging_fraction': 0.8,
    'bagging_freq': 5,
    'verbose': 0
}

model = lgb.train(
    params,
    train_data,
    num_boost_round=1000,
    valid_sets=[train_data, valid_data],
    callbacks=[
        lgb.early_stopping(stopping_rounds=50),
        lgb.log_evaluation(period=100)
    ]
)

# 特徴量重要度の確認
importance = pd.DataFrame({
    'feature': X_train.columns,
    'importance': model.feature_importance()
}).sort_values('importance', ascending=False)

4. ディープラーニング

ディープラーニングは、画像・音声・テキストなど複雑なデータを扱うために必要です。従来の機械学習(XGBoost等)は表形式データが得意ですが、ディープラーニングは非構造化データから自動的にパターンを学習できます。ただし、表形式データなら従来の機械学習の方が速くて精度も高いことが多いため、データの種類に応じて使い分けることが重要です。

PyTorch:研究・プロトタイピング向け

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader

class CustomDataset(Dataset):
    def __init__(self, X, y):
        self.X = torch.FloatTensor(X)
        self.y = torch.LongTensor(y)
    
    def __len__(self):
        return len(self.X)
    
    def __getitem__(self, idx):
        return self.X[idx], self.y[idx]

class Attention(nn.Module):
    def __init__(self, hidden_dim):
        super().__init__()
        self.attention = nn.Linear(hidden_dim, 1)
    
    def forward(self, x):
        weights = torch.softmax(self.attention(x), dim=1)
        return torch.sum(weights * x, dim=1)

# 学習ループのベストプラクティス
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)

for epoch in range(num_epochs):
    model.train()
    for batch_X, batch_y in train_loader:
        batch_X, batch_y = batch_X.to(device), batch_y.to(device)
        
        optimizer.zero_grad()
        outputs = model(batch_X)
        loss = criterion(outputs, batch_y)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
        optimizer.step()
    
    scheduler.step()

5. パフォーマンス最適化

メモリ効率化

大規模データを扱う際のメモリ管理は、データサイエンスの実務において重要な課題です。適切なデータ型の選択とチャンク処理により、メモリ使用量を大幅に削減できます。

import pandas as pd
import numpy as np

# データ型の最適化によるメモリ削減
def optimize_dtypes(df):
    """DataFrameのデータ型を最適化"""
    # 整数型の最適化
    for col in df.select_dtypes(include=['int']).columns:
        col_min = df[col].min()
        col_max = df[col].max()
        
        if col_min >= 0:
            if col_max < 255:
                df[col] = df[col].astype(np.uint8)
            elif col_max < 65535:
                df[col] = df[col].astype(np.uint16)
            elif col_max < 4294967295:
                df[col] = df[col].astype(np.uint32)
        else:
            if col_min > np.iinfo(np.int8).min and col_max < np.iinfo(np.int8).max:
                df[col] = df[col].astype(np.int8)
            elif col_min > np.iinfo(np.int16).min and col_max < np.iinfo(np.int16).max:
                df[col] = df[col].astype(np.int16)
            elif col_min > np.iinfo(np.int32).min and col_max < np.iinfo(np.int32).max:
                df[col] = df[col].astype(np.int32)
    
    # 浮動小数点型の最適化
    for col in df.select_dtypes(include=['float']).columns:
        df[col] = df[col].astype(np.float32)
    
    # カテゴリ型への変換
    for col in df.select_dtypes(include=['object']).columns:
        num_unique = df[col].nunique()
        num_total = len(df[col])
        if num_unique / num_total < 0.5:  # ユニーク値が50%未満
            df[col] = df[col].astype('category')
    
    return df

# Chunkwise処理:メモリに載らない大規模ファイル
def process_large_csv(filepath, chunksize=10000):
    """大規模CSVをチャンクごとに処理"""
    results = []
    
    for chunk in pd.read_csv(filepath, chunksize=chunksize):
        # 各チャンクを処理
        chunk = optimize_dtypes(chunk)
        processed = chunk.groupby('category')['value'].mean()
        results.append(processed)
    
    # 結果を統合
    return pd.concat(results).groupby(level=0).mean()

# Daskによる並列処理
import dask.dataframe as dd
from dask.diagnostics import ProgressBar

# 遅延評価:計算グラフを構築するだけで実行しない
ddf = dd.read_csv('large_*.csv', blocksize='64MB')
result = ddf.groupby('category').agg({'value': ['mean', 'std', 'count']})

# 実際の計算実行
with ProgressBar():
    final_result = result.compute()

# Parquet形式での保存(圧縮と高速読み込み)
ddf.to_parquet('output/', compression='snappy', engine='pyarrow')

計算高速化

Pythonのループは遅いため、ベクトル化やJITコンパイルを活用することで劇的な高速化が可能です。

from numba import jit, prange
import numpy as np

# Numbaによるコンパイル:Pure Pythonの100倍高速
@jit(nopython=True, parallel=True)
def fast_calculation(arr):
    """配列の二乗和を高速計算"""
    result = 0.0
    for i in prange(len(arr)):  # 並列ループ
        result += arr[i] ** 2
    return result

# pandasのベクトル化:apply()より高速
# 悪い例:行ごとにPython関数を呼び出し
df['result'] = df.apply(lambda row: row['a'] + row['b'] * 2, axis=1)

# 良い例:ベクトル化演算
df['result'] = df['a'] + df['b'] * 2

# np.where()による条件分岐のベクトル化
df['category'] = np.where(
    df['value'] > 100, 'high',
    np.where(df['value'] > 50, 'medium', 'low')
)

# eval()とquery()による高速評価(大規模データで有効)
# 内部的にnumexprを使用
df_filtered = df.query('age > 20 and salary < 100000')
df['new_col'] = df.eval('col_a * col_b + col_c')

# Cythonによる高速化(より高度)
# .pyx ファイルに記述してコンパイル
"""
# cython: boundscheck=False, wraparound=False
import numpy as np
cimport numpy as np

def cython_func(np.ndarray[np.float64_t, ndim=1] arr):
    cdef int i
    cdef double result = 0.0
    cdef int n = arr.shape[0]
    
    for i in range(n):
        result += arr[i] ** 2
    return result
"""

学習ロードマップ

データサイエンスの学習は段階的に進めることが重要です。以下のロードマップを参考に、実践を通じてスキルを積み上げていきましょう。

Phase 1: 基礎固め(1-2ヶ月)

  • NumPy: 配列操作、ブロードキャスティング、基本的な線形代数
  • pandas: DataFrame操作、データクリーニング、groupby、merge
  • Matplotlib: 基本的なグラフ作成

Phase 2: 実践力強化(2-3ヶ月)

  • scikit-learn: 分類・回帰アルゴリズム、Pipeline、交差検証
  • Seaborn: 統計的可視化、EDA(探索的データ分析)
  • 実践プロジェクト: Kaggleのチュートリアルに挑戦

Phase 3: 高度な技術(3-6ヶ月)

  • XGBoost/LightGBM: 勾配ブースティング、ハイパーパラメータチューニング
  • PyTorch/TensorFlow: ニューラルネットワーク、転移学習
  • パフォーマンス最適化: Numba、Dask、プロファイリング

継続的な学習

  • 最新論文の実装
  • OSSへのコントリビューション
  • 実務プロジェクトでの応用

まとめ

本記事では、データサイエンスの実務で必要となる主要Pythonライブラリを、基礎から高度なテクニックまで解説しました。

重要なポイント

  • ✅ NumPy/pandasはデータ処理の基盤であり、最優先で習得すべき
  • ✅ scikit-learnの統一されたAPIにより、機械学習の実装が容易に
  • ✅ XGBoost/LightGBMは多くの実務案件で高精度を実現
  • ✅ パフォーマンス最適化は大規模データ処理において不可欠
  • ✅ 段階的な学習とハンズオンの実践が上達の鍵

各ライブラリの公式ドキュメントには豊富な例とベストプラクティスが記載されているため、実装時は積極的に参照することを推奨します。また、Kaggleなどのコンペティションに参加することで、実践的なスキルを効率的に習得できます。

参考リソース

公式ドキュメント

実践的な学習プラットフォーム

  • Kaggle: 実データを使ったコンペティション
  • Google Colab: 無料のGPU環境
  • Fast.ai: 実践的なディープラーニングコース

最後に

最後まで読んでくださり、ありがとうございました!
本記事では、データサイエンスの実務で必要となるPythonライブラリを詳しく解説しました。
基本から機械学習まで幅広い知識が必要ですが、データ分析の分野では必須の知識であり、必ず役に立ちます。ぜひ習得してみてください!

生成AI、データ分析、深層学習を体系的に学び、プロの指導のもとで実践的なAIスキルを習得したい方、
キャリアの幅を広げたい方や副業を目指す方は、ぜひこちらからお問い合わせください。
https://b2c.aipass.tech
https://page.line.me/564fgnmw?oat_content=url&openQrModal=true

🔗 関連記事

dotConf, Inc
dotConf, Inc

Discussion