- Authors

- Name
- Youngju Kim
- @fjvbn20031
AI/ML向けPython完全ガイド
PythonはAI・機械学習の標準言語です。クリーンな構文、豊富なライブラリエコシステム、活発なコミュニティにより、研究者とエンジニアの両方に選ばれています。このガイドでは、AI/ML開発に必要なコアPythonライブラリをすべてマスターする方法を解説します。
1. Python AI/ML環境のセットアップ
Pythonバージョンの選択
AI/ML作業にはPython 3.10以降が推奨されます。Python 3.10+は構造的パターンマッチング、より明確なエラーメッセージ、改善された型ヒントを提供します。2026年現在、Python 3.12は安定しており、ほとんどのMLライブラリと互換性があります。
# Pythonバージョンを確認
python --version
python3 --version
# pyenvで特定バージョンをインストール
pyenv install 3.12.0
pyenv global 3.12.0
仮想環境のセットアップ
仮想環境はプロジェクトごとに依存関係を分離します。
venv(標準ライブラリ)
# 仮想環境の作成
python -m venv ml_env
# 有効化(Linux/Mac)
source ml_env/bin/activate
# 有効化(Windows)
ml_env\Scripts\activate
# 無効化
deactivate
conda(Anaconda/Miniconda)
# 環境を作成
conda create -n ml_env python=3.12
# 有効化
conda activate ml_env
# パッケージのインストール
conda install numpy pandas scikit-learn matplotlib
# 環境一覧
conda env list
# 環境のエクスポート
conda env export > environment.yml
# 環境の復元
conda env create -f environment.yml
Poetry(高度な依存関係管理)
# Poetryのインストール
curl -sSL https://install.python-poetry.org | python3 -
# プロジェクトの初期化
poetry new ml_project
cd ml_project
# パッケージの追加
poetry add numpy pandas scikit-learn torch
# 開発依存関係の追加
poetry add --dev pytest black flake8
# 環境内で実行
poetry run python train.py
Jupyter Notebook/Labのセットアップ
# JupyterLabのインストール
pip install jupyterlab
# カーネルの登録
python -m ipykernel install --user --name=ml_env --display-name "ML Environment"
# JupyterLabの起動
jupyter lab
# 有用な拡張機能のインストール
pip install jupyterlab-git
pip install nbformat
GPU Python環境(CUDA、cuDNN)
# CUDAバージョンを確認
nvidia-smi
nvcc --version
# PyTorchをCUDAとともにインストール(CUDA 12.1)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
# TensorFlowをGPUとともにインストール
pip install tensorflow[and-cuda]
# GPU使用可能かを確認(PyTorch)
python -c "import torch; print(torch.cuda.is_available())"
# cuDNNを確認
python -c "import torch; print(torch.backends.cudnn.version())"
必須パッケージ一覧
# requirements.txt
numpy>=1.24.0
pandas>=2.0.0
matplotlib>=3.7.0
seaborn>=0.12.0
scikit-learn>=1.3.0
scipy>=1.11.0
torch>=2.0.0
torchvision>=0.15.0
tensorflow>=2.13.0
xgboost>=1.7.0
lightgbm>=4.0.0
optuna>=3.3.0
wandb>=0.15.0
tqdm>=4.65.0
jupyterlab>=4.0.0
black>=23.0.0
flake8>=6.0.0
pytest>=7.4.0
# 一括インストール
pip install -r requirements.txt
2. NumPyをマスターする
NumPy(Numerical Python)はPythonにおける科学計算の基盤です。多次元配列と数学関数を提供し、ほとんどのMLライブラリがNumPyを内部で使用しています。
ndarrayの作成
import numpy as np
# 基本的な配列作成
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr1.shape) # (5,)
print(arr2.shape) # (2, 3)
print(arr2.dtype) # int64
print(arr2.ndim) # 2
print(arr2.size) # 6
# 特殊な配列
zeros = np.zeros((3, 4)) # すべてゼロ
ones = np.ones((2, 3, 4)) # すべて1
full = np.full((3, 3), 7) # すべて7
eye = np.eye(4) # 単位行列
empty = np.empty((2, 3)) # 初期化なし
# 範囲配列
arange = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace = np.linspace(0, 1, 5) # [0.0, 0.25, 0.5, 0.75, 1.0]
logspace = np.logspace(0, 3, 4) # [1, 10, 100, 1000]
# ランダム配列
np.random.seed(42)
rand_uniform = np.random.rand(3, 4) # 一様分布 [0, 1)
rand_normal = np.random.randn(3, 4) # 標準正規分布
rand_int = np.random.randint(0, 10, (3, 4)) # ランダム整数
# 現代的なランダムAPI(推奨)
rng = np.random.default_rng(42)
samples = rng.normal(loc=0, scale=1, size=(100, 3))
基本演算とブロードキャスティング
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[7, 8, 9], [10, 11, 12]])
# 要素ごとの算術
print(a + b) # 要素ごとの加算
print(a - b) # 要素ごとの減算
print(a * b) # 要素ごとの乗算
print(a / b) # 要素ごとの除算
print(a ** 2) # 要素ごとの二乗
print(a % 2) # 要素ごとの剰余
# ブロードキャスティング - 異なる形状の配列に対する演算
x = np.array([[1], [2], [3]]) # 形状: (3, 1)
y = np.array([10, 20, 30]) # 形状: (3,) は (1, 3) として扱われる
# ブロードキャスティング結果: (3, 3)
result = x + y
print(result)
# [[11, 21, 31],
# [12, 22, 32],
# [13, 23, 33]]
# 実践的なブロードキャスティング: バッチ正規化
data = np.random.randn(100, 10) # 100サンプル、10特徴
mean = data.mean(axis=0) # 特徴ごとの平均(形状: 10,)
std = data.std(axis=0) # 特徴ごとの標準偏差(形状: 10,)
normalized = (data - mean) / std # ブロードキャスティング正規化
print(normalized.mean(axis=0).round(10)) # ほぼ0
print(normalized.std(axis=0).round(10)) # ほぼ1
インデックス、スライス、ブールインデックス
import numpy as np
arr = np.arange(24).reshape(4, 6)
print(arr)
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
# 基本的なインデックス
print(arr[0, 0]) # 0
print(arr[3, 5]) # 23
print(arr[-1, -1]) # 23
# スライス
print(arr[1:3, 2:5]) # 行1-2、列2-4
print(arr[:, 0]) # 全行、列0
print(arr[::2, ::2]) # 2行おき、2列おき
# ファンシーインデックス
rows = np.array([0, 2])
cols = np.array([1, 4])
print(arr[rows, cols]) # [arr[0,1], arr[2,4]] = [1, 16]
# ブールインデックス(マスキング)
mask = arr > 12
print(arr[mask]) # 12より大きい要素
# 条件によるフィルタリング
data = np.array([1, -2, 3, -4, 5, -6])
positive = data[data > 0] # [1, 3, 5]
# np.where - 条件付き選択
result = np.where(data > 0, data, 0) # 正の値はそのまま、負の値は0に
print(result) # [1, 0, 3, 0, 5, 0]
形状変換
import numpy as np
arr = np.arange(12)
# reshape
a = arr.reshape(3, 4)
b = arr.reshape(2, 2, 3)
c = arr.reshape(-1, 4) # -1は自動推論: (3, 4) になる
# flatten vs ravel
flat1 = a.flatten() # 常にコピーを返す
flat2 = a.ravel() # 可能な場合はビューを返す(メモリ効率的)
# transpose
mat = np.random.randn(3, 4)
transposed = mat.T
transposed2 = mat.transpose()
# squeeze と expand_dims
x = np.array([[[1, 2, 3]]]) # 形状: (1, 1, 3)
squeezed = np.squeeze(x) # (3,)
expanded = np.expand_dims(squeezed, axis=0) # (1, 3)
# 配列のスタック
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
hstack = np.hstack([a, b]) # 水平スタック (2, 4)
vstack = np.vstack([a, b]) # 垂直スタック (4, 2)
数学関数
import numpy as np
x = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
# 三角関数
sin_x = np.sin(x)
cos_x = np.cos(x)
tan_x = np.tan(x)
# 指数と対数
exp_x = np.exp(x) # e^x
log_x = np.log(x + 1) # 自然対数 (ln)
log2_x = np.log2(x + 1) # 底2の対数
log10_x = np.log10(x + 1)
# シグモイドとソフトマックス
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def softmax(x):
e_x = np.exp(x - x.max()) # 数値安定のため最大値を引く
return e_x / e_x.sum()
z = np.array([1.0, 2.0, 3.0])
print(sigmoid(z)) # [0.731, 0.880, 0.952]
print(softmax(z)) # [0.090, 0.245, 0.665]
線形代数
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 行列積
C = np.dot(A, B) # 古典的な方法
C = A @ B # Python 3.5+で推奨
C = np.matmul(A, B) # 2次元では np.dot と同じ
# バッチ行列積(3次元+)
batch_A = np.random.randn(32, 3, 4)
batch_B = np.random.randn(32, 4, 5)
batch_C = batch_A @ batch_B # (32, 3, 5)
# 線形代数関数
det = np.linalg.det(A) # 行列式
inv = np.linalg.inv(A) # 逆行列
rank = np.linalg.matrix_rank(A) # ランク
trace = np.trace(A) # トレース
# 固有値分解
eigenvalues, eigenvectors = np.linalg.eig(A)
# 特異値分解(SVD)
U, S, Vt = np.linalg.svd(A)
# 線形方程式 Ax = b を解く
b = np.array([5, 6])
x = np.linalg.solve(A, b)
# ノルム
v = np.array([3, 4])
l1_norm = np.linalg.norm(v, ord=1) # L1ノルム: 7
l2_norm = np.linalg.norm(v, ord=2) # L2ノルム: 5
inf_norm = np.linalg.norm(v, ord=np.inf) # 最大ノルム: 4
ベクトル化演算 vs forループ
import numpy as np
import time
n = 1_000_000
a = np.random.randn(n)
b = np.random.randn(n)
# forループ
start = time.time()
result_loop = []
for i in range(n):
result_loop.append(a[i] * b[i])
loop_time = time.time() - start
print(f"forループ: {loop_time:.4f}s")
# ベクトル化
start = time.time()
result_vec = a * b
vec_time = time.time() - start
print(f"ベクトル化: {vec_time:.4f}s")
print(f"高速化倍率: {loop_time / vec_time:.1f}x")
# 通常100〜1000倍高速
実践:NumPyのみによるニューラルネットワークの順伝播
import numpy as np
class SimpleNeuralNetwork:
"""NumPyのみで実装した2層ニューラルネットワーク"""
def __init__(self, input_size, hidden_size, output_size, seed=42):
np.random.seed(seed)
# He初期化
self.W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2.0 / input_size)
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.randn(hidden_size, output_size) * np.sqrt(2.0 / hidden_size)
self.b2 = np.zeros((1, output_size))
def relu(self, z):
return np.maximum(0, z)
def relu_derivative(self, z):
return (z > 0).astype(float)
def softmax(self, z):
exp_z = np.exp(z - z.max(axis=1, keepdims=True))
return exp_z / exp_z.sum(axis=1, keepdims=True)
def forward(self, X):
# 層1
self.Z1 = X @ self.W1 + self.b1
self.A1 = self.relu(self.Z1)
# 層2
self.Z2 = self.A1 @ self.W2 + self.b2
self.A2 = self.softmax(self.Z2)
return self.A2
def cross_entropy_loss(self, y_pred, y_true):
m = y_true.shape[0]
log_probs = -np.log(y_pred[range(m), y_true] + 1e-8)
return log_probs.mean()
def train(self, X, y, epochs=100, learning_rate=0.01):
losses = []
for epoch in range(epochs):
y_pred = self.forward(X)
loss = self.cross_entropy_loss(y_pred, y)
losses.append(loss)
if epoch % 10 == 0:
acc = (y_pred.argmax(axis=1) == y).mean()
print(f"エポック {epoch:3d}: Loss={loss:.4f}, Acc={acc:.4f}")
return losses
# テスト
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=1000, n_features=20,
n_classes=3, n_informative=15,
random_state=42)
nn = SimpleNeuralNetwork(input_size=20, hidden_size=64, output_size=3)
losses = nn.train(X, y, epochs=50, learning_rate=0.1)
3. Pandasをマスターする
Pandasは表形式データを扱うためのコアライブラリです。DataFrameとSeriesデータ構造を提供し、データクリーニング、変換、分析のあらゆるステップをサポートします。
SeriesとDataFrame
import pandas as pd
import numpy as np
# Seriesの作成
s1 = pd.Series([1, 2, 3, 4, 5])
s2 = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
s3 = pd.Series({'x': 100, 'y': 200, 'z': 300})
print(s2['a']) # 10
print(s2[['a', 'c']]) # a=10, c=30
# DataFrameの作成
data = {
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 22],
'score': [88.5, 92.3, 78.1, 95.7, 83.2],
'passed': [True, True, False, True, True]
}
df = pd.DataFrame(data)
print(df.head())
print(df.tail(3))
print(df.info())
print(df.describe())
print(df.dtypes)
print(df.shape) # (5, 4)
データの読み書き
import pandas as pd
# CSV
df_csv = pd.read_csv('data.csv',
sep=',',
header=0,
index_col=0,
parse_dates=['date'],
encoding='utf-8',
na_values=['N/A', 'null', ''])
df_csv.to_csv('output.csv', index=False, encoding='utf-8')
# Excel
df_excel = pd.read_excel('data.xlsx', sheet_name='Sheet1', header=0)
df_excel.to_excel('output.xlsx', sheet_name='Result', index=False)
# JSON
df_json = pd.read_json('data.json', orient='records')
df_json.to_json('output.json', orient='records', indent=2)
# Parquet(高性能な列指向フォーマット)
df.to_parquet('data.parquet', engine='pyarrow', compression='snappy')
df_parquet = pd.read_parquet('data.parquet')
# SQL(SQLiteの例)
import sqlite3
conn = sqlite3.connect('database.db')
df_sql = pd.read_sql_query("SELECT * FROM users WHERE age > 25", conn)
df.to_sql('new_table', conn, if_exists='replace', index=False)
locとilocによるインデックス
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': range(10),
'B': range(10, 20),
'C': range(20, 30)
}, index=[f'row{i}' for i in range(10)])
# loc: ラベルベースのインデックス
print(df.loc['row0', 'A']) # 単一の値
print(df.loc['row0':'row3', 'A':'B']) # 範囲(終端を含む)
print(df.loc[['row1', 'row5'], 'C']) # リスト
# iloc: 位置ベースのインデックス
print(df.iloc[0, 0]) # 行0、列0
print(df.iloc[0:4, 0:2]) # 範囲(終端を含まない)
print(df.iloc[[1, 5], 2]) # リスト
# 条件ベースの選択
mask = df['A'] > 5
filtered = df[mask]
filtered2 = df[df['B'].between(12, 17)]
filtered3 = df.query('A > 5 and B < 18')
欠損値の処理
import pandas as pd
import numpy as np
# 欠損値を含むデータの作成
df = pd.DataFrame({
'age': [25, np.nan, 35, np.nan, 22],
'income': [50000, 60000, np.nan, 80000, np.nan],
'city': ['Seoul', 'Busan', None, 'Incheon', 'Seoul'],
'score': [88.5, 92.3, 78.1, np.nan, 83.2]
})
# 欠損値の確認
print(df.isnull().sum()) # 列ごとの件数
print(df.isnull().sum() / len(df) * 100) # 欠損率
# 欠損値の削除
df_dropped_rows = df.dropna() # NaNを含む行を削除
df_dropped_cols = df.dropna(axis=1) # NaNを含む列を削除
df_thresh = df.dropna(thresh=3) # 少なくとも3つの非NaN値を持つ行を保持
# 欠損値の補完
df_filled_0 = df.fillna(0)
df_filled_mean = df.fillna(df.mean())
df_filled_dict = df.fillna({
'age': df['age'].mean(),
'income': df['income'].median(),
'city': 'Unknown',
'score': df['score'].mean()
})
# 前方/後方補完
df_ffill = df.fillna(method='ffill')
df_bfill = df.fillna(method='bfill')
# 補間
df_interpolated = df.interpolate(method='linear')
データ変換
import pandas as pd
import numpy as np
df = pd.DataFrame({
'text': ['hello world', 'PYTHON IS GREAT', 'data science'],
'value': [1, 2, 3],
'category': ['A', 'B', 'A']
})
# apply: 関数を適用
df['text_upper'] = df['text'].apply(str.upper)
df['text_length'] = df['text'].apply(len)
# 複数の列を同時に処理
def feature_engineer(row):
return pd.Series({
'value_squared': row['value'] ** 2,
'category_is_A': int(row['category'] == 'A')
})
new_features = df.apply(feature_engineer, axis=1)
df = pd.concat([df, new_features], axis=1)
# map: マッピングテーブルを適用
category_map = {'A': 'Alpha', 'B': 'Beta', 'C': 'Gamma'}
df['category_name'] = df['category'].map(category_map)
# 文字列操作(ベクトル化)
texts = pd.Series(['Hello World', 'Python 3.12', 'Machine Learning'])
print(texts.str.lower())
print(texts.str.split())
print(texts.str.contains('Python'))
print(texts.str.extract(r'(\w+)\s+(\w+)'))
GroupBy集計
import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({
'team': np.random.choice(['A', 'B', 'C'], 100),
'role': np.random.choice(['dev', 'ds', 'pm'], 100),
'score': np.random.randint(60, 100, 100),
'salary': np.random.randint(3000, 8000, 100)
})
# 基本的なgroupby
grouped = df.groupby('team')
print(grouped['score'].mean())
print(grouped['salary'].describe())
# 複数キー
multi_grouped = df.groupby(['team', 'role'])
print(multi_grouped['score'].mean().unstack())
# カスタム集計
agg_result = df.groupby('team').agg(
avg_score=('score', 'mean'),
total_salary=('salary', 'sum'),
count=('score', 'count'),
max_score=('score', 'max'),
min_salary=('salary', 'min')
)
DataFrameの結合
import pandas as pd
users = pd.DataFrame({
'user_id': [1, 2, 3, 4, 5],
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 22]
})
orders = pd.DataFrame({
'order_id': [101, 102, 103, 104, 105, 106],
'user_id': [1, 2, 1, 3, 5, 6],
'amount': [150, 250, 80, 320, 190, 440]
})
# 内部結合(積集合)
inner = pd.merge(users, orders, on='user_id', how='inner')
# 左結合
left = pd.merge(users, orders, on='user_id', how='left')
# 右結合
right = pd.merge(users, orders, on='user_id', how='right')
# 外部結合(和集合)
outer = pd.merge(users, orders, on='user_id', how='outer')
# concat
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
vertical = pd.concat([df1, df2], axis=0, ignore_index=True)
4. MatplotlibとSeabornによる可視化
基本的なプロット
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# 折れ線グラフ
x = np.linspace(0, 2 * np.pi, 100)
axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2, label='sin(x)')
axes[0, 0].plot(x, np.cos(x), 'r--', linewidth=2, label='cos(x)')
axes[0, 0].set_title('三角関数')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 棒グラフ
categories = ['分類', '回帰', 'クラスタリング', '次元削減']
values = [85, 72, 68, 91]
bars = axes[0, 1].bar(categories, values,
color=['#3498db', '#e74c3c', '#2ecc71', '#f39c12'])
axes[0, 1].set_title('アルゴリズム精度')
axes[0, 1].set_ylabel('精度 (%)')
# 散布図
np.random.seed(42)
x_scatter = np.random.randn(100)
y_scatter = 2 * x_scatter + np.random.randn(100) * 0.5
axes[0, 2].scatter(x_scatter, y_scatter, alpha=0.6, c=y_scatter, cmap='viridis')
axes[0, 2].set_title('散布図')
# ヒストグラム
data = np.concatenate([
np.random.normal(0, 1, 500),
np.random.normal(4, 1.5, 300)
])
axes[1, 0].hist(data, bins=50, density=True, alpha=0.7, color='steelblue')
axes[1, 0].set_title('データ分布')
plt.tight_layout()
plt.savefig('basic_plots.png', dpi=150, bbox_inches='tight')
plt.show()
Seaborn統計的可視化
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
sns.set_theme(style='whitegrid', palette='husl', font_scale=1.2)
# サンプルデータ
df = pd.DataFrame({
'model': np.repeat(['ResNet', 'VGG', 'EfficientNet', 'ViT'], 50),
'accuracy': np.concatenate([
np.random.normal(92, 2, 50),
np.random.normal(88, 3, 50),
np.random.normal(94, 1.5, 50),
np.random.normal(95, 2.5, 50)
]),
'params_M': np.concatenate([
np.random.normal(25, 2, 50),
np.random.normal(138, 5, 50),
np.random.normal(5.3, 0.3, 50),
np.random.normal(86, 3, 50)
])
})
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# バイオリンプロット
sns.violinplot(data=df, x='model', y='accuracy', ax=axes[0, 0])
axes[0, 0].set_title('モデルごとの精度分布')
# ヒートマップ(相関行列)
corr_data = df[['accuracy', 'params_M']].corr()
sns.heatmap(corr_data, annot=True, fmt='.2f', cmap='RdYlGn',
center=0, ax=axes[0, 1])
axes[0, 1].set_title('相関行列')
plt.tight_layout()
plt.savefig('seaborn_plots.png', dpi=150, bbox_inches='tight')
plt.show()
5. Scikit-learnによる機械学習
前処理
from sklearn.preprocessing import (
StandardScaler, MinMaxScaler, RobustScaler, LabelEncoder, OneHotEncoder
)
import numpy as np
X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], dtype=float)
# 標準化(平均0、標準偏差1)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print(f"StandardScaler後の平均: {X_scaled.mean(axis=0).round(10)}")
print(f"StandardScaler後の標準偏差: {X_scaled.std(axis=0).round(10)}")
# 最小最大スケーリング([0, 1]の範囲)
minmax = MinMaxScaler()
X_minmax = minmax.fit_transform(X)
print(f"MinMaxScaler後の最小値: {X_minmax.min(axis=0)}")
print(f"MinMaxScaler後の最大値: {X_minmax.max(axis=0)}")
# ロバストスケーラー(外れ値に強い)
robust = RobustScaler()
X_robust = robust.fit_transform(X)
線形モデル
from sklearn.linear_model import LogisticRegression, Ridge, Lasso
from sklearn.datasets import make_classification, make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, r2_score
import numpy as np
# 分類
X, y = make_classification(n_samples=1000, n_features=20,
n_classes=2, n_informative=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
lr = LogisticRegression(C=1.0, max_iter=1000, random_state=42)
lr.fit(X_train, y_train)
print(f"ロジスティック回帰の精度: {accuracy_score(y_test, lr.predict(X_test)):.4f}")
# 回帰(Ridge)
X_reg, y_reg = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=42)
X_tr, X_te, y_tr, y_te = train_test_split(X_reg, y_reg, test_size=0.2, random_state=42)
ridge = Ridge(alpha=1.0)
ridge.fit(X_tr, y_tr)
print(f"Ridge R2: {r2_score(y_te, ridge.predict(X_te)):.4f}")
ツリーベースのモデル
from sklearn.ensemble import (
RandomForestClassifier, GradientBoostingClassifier
)
import xgboost as xgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import numpy as np
X, y = make_classification(n_samples=1000, n_features=20,
n_classes=2, n_informative=10,
random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
models = {
'ランダムフォレスト': RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1),
'勾配ブースティング': GradientBoostingClassifier(n_estimators=100, random_state=42),
'XGBoost': xgb.XGBClassifier(n_estimators=100, random_state=42, eval_metric='logloss'),
}
for name, model in models.items():
model.fit(X_train, y_train)
acc = (model.predict(X_test) == y_test).mean()
print(f"{name}: {acc:.4f}")
モデル評価とクロスバリデーション
from sklearn.model_selection import cross_val_score, StratifiedKFold, GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
rf = RandomForestClassifier(n_estimators=100, random_state=42)
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(rf, X, y, cv=cv, scoring='accuracy', n_jobs=-1)
print(f"CV精度: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
# GridSearchCV
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 5, 10],
'min_samples_split': [2, 5, 10]
}
grid_search = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid, cv=5, scoring='accuracy', n_jobs=-1, verbose=1
)
grid_search.fit(X, y)
print(f"最適パラメータ: {grid_search.best_params_}")
print(f"最高CVスコア: {grid_search.best_score_:.4f}")
パイプライン
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
import pandas as pd
import numpy as np
np.random.seed(42)
n = 500
df = pd.DataFrame({
'age': np.random.randint(18, 70, n).astype(float),
'income': np.random.randint(20000, 100000, n).astype(float),
'education': np.random.choice(['高卒', '学士', '修士', '博士'], n),
'city': np.random.choice(['東京', '大阪', '名古屋', '福岡'], n),
'target': np.random.randint(0, 2, n)
})
X = df.drop('target', axis=1)
y = df['target']
numeric_features = ['age', 'income']
categorical_features = ['education', 'city']
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('encoder', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
])
preprocessor = ColumnTransformer(transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
full_pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', RandomForestClassifier(n_estimators=100, random_state=42))
])
from sklearn.model_selection import cross_val_score
scores = cross_val_score(full_pipeline, X, y, cv=5, scoring='accuracy')
print(f"パイプラインCV精度: {scores.mean():.4f} +/- {scores.std():.4f}")
6. Python性能最適化
リスト内包表記 vs map vs for
import time
import numpy as np
n = 1_000_000
data = list(range(n))
# forループ
start = time.time()
result_for = []
for x in data:
result_for.append(x ** 2)
print(f"forループ: {time.time() - start:.4f}s")
# リスト内包表記
start = time.time()
result_lc = [x ** 2 for x in data]
print(f"リスト内包表記: {time.time() - start:.4f}s")
# map
start = time.time()
result_map = list(map(lambda x: x ** 2, data))
print(f"Map: {time.time() - start:.4f}s")
# NumPyベクトル化
arr = np.array(data)
start = time.time()
result_np = arr ** 2
print(f"NumPy: {time.time() - start:.4f}s")
ジェネレーター
import sys
# リストとジェネレーターのメモリ比較
list_comp = [x**2 for x in range(1_000_000)]
gen_expr = (x**2 for x in range(1_000_000))
print(f"リストサイズ: {sys.getsizeof(list_comp):,} bytes") # ~8MB
print(f"ジェネレーターサイズ: {sys.getsizeof(gen_expr)} bytes") # ~120 bytes
# ジェネレーター関数
def infinite_data_loader(dataset, batch_size=32):
"""無限データローダージェネレーター"""
while True:
indices = np.random.permutation(len(dataset))
for i in range(0, len(dataset), batch_size):
batch_indices = indices[i:i + batch_size]
yield dataset[batch_indices]
並列処理
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
def cpu_intensive_task(n):
return sum(i**2 for i in range(n))
def io_bound_task(url):
time.sleep(0.1)
return f"フェッチ完了: {url}"
# ThreadPoolExecutor: I/Oバウンドタスクに最適
urls = [f"https://example.com/data/{i}" for i in range(20)]
start = time.time()
with ThreadPoolExecutor(max_workers=10) as executor:
results = list(executor.map(io_bound_task, urls))
print(f"スレッドプール時間: {time.time() - start:.2f}s")
# ProcessPoolExecutor: CPUバウンドタスクに最適
numbers = [1_000_000] * 8
start = time.time()
with ProcessPoolExecutor(max_workers=4) as executor:
results = list(executor.map(cpu_intensive_task, numbers))
print(f"プロセスプール時間: {time.time() - start:.2f}s")
7. AI/MLユーティリティライブラリ
tqdm - プログレスバー
from tqdm import tqdm, trange
import time
# 基本的な使用方法
for i in tqdm(range(100)):
time.sleep(0.01)
# カスタム説明
items = list(range(50))
for item in tqdm(items, desc='処理中', unit='sample'):
pass
# ネストされたプログレスバー
for epoch in trange(10, desc='エポック'):
for batch in trange(100, desc='バッチ', leave=False):
pass
# メトリクスつきの手動更新
with tqdm(total=100, desc='学習中') as pbar:
for i in range(10):
pbar.update(10)
pbar.set_postfix({'loss': 0.5 - i * 0.04, 'acc': 0.7 + i * 0.02})
Weights and Biases(wandb)- 実験追跡
import wandb
import numpy as np
wandb.init(
project="ml-experiment",
name="run-001",
config={
"learning_rate": 0.001,
"batch_size": 32,
"epochs": 100,
"model": "ResNet50",
"optimizer": "AdamW"
}
)
for epoch in range(100):
train_loss = 1.0 - epoch * 0.009 + np.random.normal(0, 0.01)
val_loss = 1.0 - epoch * 0.008 + np.random.normal(0, 0.02)
train_acc = epoch * 0.009 + np.random.normal(0, 0.01)
val_acc = epoch * 0.008 + np.random.normal(0, 0.02)
wandb.log({
"epoch": epoch,
"train/loss": train_loss,
"val/loss": val_loss,
"train/acc": train_acc,
"val/acc": val_acc,
"learning_rate": 0.001 * (0.95 ** epoch)
})
wandb.finish()
pytest - テスト
# tests/test_preprocessing.py
import pytest
import numpy as np
import pandas as pd
def normalize(x):
return (x - x.mean()) / x.std()
class TestNormalize:
def test_mean_zero(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
result = normalize(x)
assert abs(result.mean()) < 1e-10
def test_std_one(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
result = normalize(x)
assert abs(result.std() - 1.0) < 1e-10
def test_shape_preserved(self):
x = np.random.randn(10, 5)
result = normalize(x)
assert result.shape == x.shape
@pytest.fixture
def sample_df():
return pd.DataFrame({
'value': [1.0, 2.0, np.nan, 4.0, 5.0],
'label': ['a', 'b', 'c', 'd', 'e']
})
def test_dropna(sample_df):
result = sample_df.dropna()
assert result.isnull().sum().sum() == 0
# 実行方法: pytest tests/ -v --coverage
まとめ
このガイドではAI/ML開発に必要なPythonエコシステムの主要部分をカバーしました:
- 環境構築: venv、conda、poetryによるプロジェクト分離
- NumPy: ベクトル化演算による高性能数値計算
- Pandas: データの前処理と分析パイプラインの構築
- Matplotlib/Seaborn: インサイトを引き出す豊富な可視化
- Scikit-learn: 前処理からモデル評価まで完全なMLワークフロー
- 性能最適化: ジェネレーター、並列処理、Numba JIT
- ユーティリティ: tqdm、wandb、pytest
実際のMLプロジェクトでは、これらのツールが組み合わさって完全なパイプラインを構築します:データの読み込み、前処理、特徴エンジニアリング、モデルの学習、評価、デプロイ。より深く学ぶには各ツールの公式ドキュメントを参照してください。