新米データサイエンティストの日常（架空）｜Kaggle画像コンペ編

# はじめに
今回は、「新米データサイエンティストの日常」シリーズの第４弾になります。
新米データサイエンティストが躓きがちなテーマについて、先輩データサイエンティストと会話しているシーンをChatGPTに生成してもらいました。

第３弾はこちら↓

https://qiita.com/UKI_datascience/items/e44a277973d1305a28aa

---

# 登場人物（架空）
- 佐藤：新卒１年目の新米データサイエンティスト。Kaggleは初心者で、2D画像コンペの経験もなし。
- 田中：入社５年目の先輩データサイエンティスト。Kaggle GrandMaster

---

### **Kaggleの3D画像コンペに挑戦！**
#### **1. コンペの選定と基本情報の確認**
**佐藤**：「田中さん、Kaggleの3D画像コンペに挑戦しようと思うんですが、何から始めたらいいですか？そもそも3D画像ってどう扱うんでしょうか？」

**田中**：「いいね！まずは **Kaggleのコンペページ** をしっかり読もう。3D画像コンペは例えば **RSNA Intracranial Hemorrhage Detection** や **Shin MRI Segmentation Challenge** みたいな医療系が多いよ。対象がCTやMRIのことも多いから、データ形式やタスクを把握するのが最初のステップだね。」

**佐藤**：「Kaggleページではどこを重点的に読めばいいですか？」

**田中**：「**Overview, Evaluation, Data** の3つだね。  
1. **Overview** でタスクの目的を確認（分類なのか、検出なのか、セグメンテーションなのか）  
2. **Evaluation** で評価指標を把握（AUCなのか、Dice係数なのか）  
3. **Data** でデータ形式を確認（DICOMやNIfTI、.npz形式など）」

**佐藤**：「なるほど… 3Dデータの形式って見たことないですが、普通の画像と何が違うんですか？」

**田中**：「3Dデータは**ボリュームデータ（Voxel）** で構成されているんだ。2D画像はH×W（高さ×幅）だけど、3Dは H×W×D（奥行き）になる。例えば、CTスキャンなら **スライス画像の集合** になるし、MRIなら**ボクセルデータ** で3D空間を表現しているんだ。」

---

#### **2. 環境構築とデータの可視化**
**佐藤**：「3Dデータの確認ってどうやるんですか？普通の画像みたいに `plt.imshow()` で表示できるんですか？」

**田中**：「うーん、それだと1スライス（2D）しか見れないね。3Dデータの可視化には `SimpleITK` や `nibabel` を使うと便利だよ。」

```python
import nibabel as nib
import matplotlib.pyplot as plt

# NIfTIデータの読み込み
img = nib.load("sample.nii")
data = img.get_fdata()

# スライスを表示
plt.imshow(data[:, :, data.shape[2]//2], cmap="gray")
plt.show()
```

**佐藤**：「なるほど！スライスごとに確認するんですね。でも3D全体を見たい場合はどうすればいいですか？」

**田中**：「`plotly` を使ってインタラクティブに3Dボリュームを確認できるよ。」

```python
import plotly.figure_factory as ff

fig = ff.create_trisurf(data=data[:, :, ::2])  # スライスを間引く
fig.show()
```

**佐藤**：「おお、直感的にデータを見られますね！」

---

#### **3. 前処理**
**佐藤**：「3Dデータの前処理ってどんなことをするんですか？」

**田中**：「2Dと似ている部分もあるけど、違いもある。例えば…  
- **リサンプリング**（ボクセルサイズを統一）  
- **ノイズ除去**（MRIならN4ITK補正）  
- **強度正規化**（Zスコア正規化）  
- **スライス選択**（不要な部分を除外）  
- **データ拡張**（3D回転、スケーリング）  

例えば、リサンプリングは `SimpleITK` でできるよ。」

```python
import SimpleITK as sitk

def resample_image(image, new_spacing=[1.0, 1.0, 1.0]):
    spacing = image.GetSpacing()
    resample = sitk.ResampleImageFilter()
    resample.SetOutputSpacing(new_spacing)
    resample.SetSize([int(round(s * old / new)) for s, old, new in zip(image.GetSize(), spacing, new_spacing)])
    return resample.Execute(image)

resampled_img = resample_image(img)
```

**佐藤**：「これは2Dのリサイズみたいなものですか？」

**田中**：「そうそう。でも、3Dは**異なる解像度のデータが混在しがち** だから、統一しないとモデルがうまく学習できないんだ。」

---

#### **4. モデルの選定**
**佐藤**：「3Dデータを扱うには、どんなモデルを使えばいいですか？」

**田中**：「代表的なものは **3D CNN** だね。例えば `3D U-Net` や `V-Net` が有名。PyTorchなら `torchio` や `MONAI` が便利。」

```python
import torch
import torch.nn as nn

class Simple3DCNN(nn.Module):
    def __init__(self):
        super(Simple3DCNN, self).__init__()
        self.conv1 = nn.Conv3d(1, 16, kernel_size=3, padding=1)
        self.pool = nn.MaxPool3d(2)
        self.fc = nn.Linear(16 * 32 * 32 * 32, 2)  # 32x32x32に縮小

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = torch.flatten(x, start_dim=1)
        x = self.fc(x)
        return x
```

**佐藤**：「これは2D CNNと同じ構造ですが、3D版になった感じですね！」

**田中**：「その通り！でも**計算コストが高い** から、メモリ管理が重要になるよ。」

---

#### **5. モデル学習と評価**
**佐藤**：「学習と評価のポイントは何ですか？」

**田中**：「ポイントは3つ！  
1. **適切なロス関数を選ぶ**（Dice損失やBCE）  
2. **適切なデータ拡張**（3D回転やランダムスライス）  
3. **学習率スケジューリング**（Cosine Annealingなど）  

また、評価指標には **AUC, Dice, IoU** などを確認するといいね。」

---

### **まとめ**
**佐藤**：「3Dデータの扱いは奥が深いですね…！」

**田中**：「そうだね。でも、基本は**データをよく観察し、適切な前処理をし、適切なモデルを選ぶ** こと。最初はシンプルなモデルから試して、徐々に精度を上げていこう！」

**佐藤**：「はい！まずはデータの可視化と前処理から頑張ります！」