SQL ⇄ Pandas 変換チートシート（上級対応）

# はじめに
PtyhonのPandasはSQLの操作と対応づけると理解しやすいので、

## 📘 1. 型の対応表

| 概念         | SQL                             | Pandas                         | 戻り値型            |
|--------------|----------------------------------|--------------------------------|---------------------|
| テーブル全体   | `table`                         | `df`                           | `pd.DataFrame`      |
| 単一列       | `SELECT col FROM table`         | `df['col']`                    | `pd.Series`         |
| 複数列       | `SELECT col1, col2`             | `df[['col1', 'col2']]`         | `pd.DataFrame`      |
| 単一行       | `SELECT * FROM table WHERE id=1`| `df.loc[1]` or `df.iloc[1]`    | `pd.Series`         |
| セル         | `SELECT col WHERE id=1`         | `df.loc[1, 'col']`             | スカラー（int等）   |

---

## 🛠️ 2. 操作の対応表

### 🔹 基本操作

| SQL         | Pandas                          | 備考                        |
|--------------|----------------------------------|-----------------------------|
| WHERE句      | `df[df['col'] > 100]`           | 条件抽出                     |
| SELECT句     | `df[['col1', 'col2']]`          | 列の選択                     |
| ORDER BY     | `df.sort_values('col')`         | 昇順 / 降順（`ascending=`） |
| LIMIT        | `df.head(n)`                    | 上位n件                       |

---

### 🔹 集計とグループ化

| SQL                          | Pandas                                              | 備考                       |
|-----------------------------|-----------------------------------------------------|----------------------------|
| GROUP BY                    | `df.groupby('col')`                                 | `.mean()`, `.sum()`など適用 |
| GROUP BY 複数列              | `df.groupby(['col1', 'col2'])`                      |                            |
| HAVING                      | `.filter(lambda x: 条件)`                           | groupbyのあとで使う        |
| COUNT(*)                    | `df['col'].count()` or `df.groupby(...).size()`    |                            |
| DISTINCT                    | `df['col'].unique()` or `df.drop_duplicates()`     |                            |

---

### 🔹 結合（JOIN）

| SQL                            | Pandas                                                    | 備考                          |
|--------------------------------|------------------------------------------------------------|-------------------------------|
| INNER JOIN                     | `pd.merge(df1, df2, on='key')`                            | デフォルトinner               |
| LEFT OUTER JOIN                | `pd.merge(df1, df2, on='key', how='left')`                |                               |
| RIGHT OUTER JOIN               | `pd.merge(df1, df2, on='key', how='right')`               |                               |
| FULL OUTER JOIN                | `pd.merge(df1, df2, on='key', how='outer')`               |                               |
| JOIN 複数キー                  | `pd.merge(df1, df2, on=['key1', 'key2'])`                 |                               |

---

### 🔹 サブクエリ的処理・列操作

| SQL                              | Pandas                                                  | 備考                             |
|----------------------------------|----------------------------------------------------------|----------------------------------|
| サブクエリ                       | `.query()` or `.apply()`                                 | 高度な条件に使える               |
| 新列追加                         | `df['new'] = ...`                                        | 列演算や定数で追加               |
| CASE WHEN                        | `np.where(条件, 値1, 値2)`                               | 条件に応じて値を変更             |
| 列の削除                         | `df.drop('col', axis=1)`                                 | axis=1で列方向指定               |
| 列名変更                         | `df.rename(columns={'old': 'new'})`                      |                                  |

---

### 🔹 ウィンドウ関数（Window Functions）

| SQL                           | Pandas                                                   | 備考                             |
|--------------------------------|-----------------------------------------------------------|----------------------------------|
| `ROW_NUMBER() OVER (...)`     | `df.sort_values(...).reset_index()`                      | 連番は `df.reset_index()`など    |
| `RANK()`, `DENSE_RANK()`      | `df['rank'] = df['col'].rank(method='dense')`           | `method='min', 'dense', etc.`   |
| `MOVING AVG`（移動平均）      | `df['col'].rolling(window=3).mean()`                     | 窓幅指定                         |
| `CUMSUM`, `CUMAVG`            | `df['col'].cumsum()`, `expanding().mean()`               | 累積処理                         |
| PARTITION BY + ORDER BY       | `df.groupby('key')['col'].rolling(...)`（やや複雑）      | GroupBy + Rollingの組み合わせ   |

---

## 🔁 3. 型の流れ図（アクセスによる変化）
DataFrame（df）
├─ df['col'] → Series（1列）
├─ df[['col1', 'col2']] → DataFrame（複数列）
├─ df.loc[3] → Series（1行）
├─ df.iloc[3, 2] → スカラー（セル1つ）

- `.loc[]`：ラベル指定（index/列名）
- `.iloc[]`：番号指定（位置ベース）
- `.at[]`, `.iat[]`：高速スカラーアクセス

---

## ⚠️ 4. よくある混乱と注意点

- `df['col']` → Series、`df[['col']]` → DataFrame（1列でも型が異なる）
- `groupby()` は即集計しないと GroupBy オブジェクトになる
- `.apply()` の戻り値で列 or 行の形が大きく変わる（要注意）
- 行抽出の条件式は Series 型になる → `df[条件]` の形で使う
- `query()` は変数を使うとき `@var` のように書く必要あり

---

## ✅ おまけ：PandasでSQLライクに書くTips

```python
df.query('price > 100 and volume < 1000')
df.groupby('sector')['price'].mean()
df.assign(change = df['close'] - df['open'])