分析コンペに挑戦してみた

<h2>
問題

不動産の価格予測の問題に取り組んでみた。
https://competition.nishika.com/competitions/mansion_pra/summary

データ分析の流れや考え方を学ぶために取り組んだ。
流れを振り返るためにも備忘録としてアウトプットする。

<h2>
取り組み方

下記の流れで取り組んだ。
<h3>
1. データの確認（データ型、欠損値の量、データ量とカラム）

![スクリーンショット 2023-08-08 1.06.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330320/8d26445c-87fa-73a7-bb10-d352fae2836a.png)

<h3>
2. 使うデータを絞る。

絞り方は下記にあてはまるものを削除した。
・nullが半分以上あるもの
・カテゴリー変数かつ取る値が多すぎて、数値化しても無意味そうなもの


よって使えそうなカラムは下記と考えた。

![スクリーンショット 2023-08-08 1.11.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330320/11590a85-9dcd-a6fb-6fd8-8a05f0343228.png)


<h3>
3. カテゴリー変数を数値に変換する。

便利なLabelEncoderを使った。

```python
from sklearn.preprocessing import LabelEncoder

realestate_data = df.copy()
def encode_categorical(df, columns):
    for col in columns:
        LE = LabelEncoder()
        df[col] = LE.fit_transform(df[col])
    return df

realestate_data = encode_categorical(realestate_data,['都道府県名','間取り', '建物の構造','用途','都市計画','改装'])
```

<h3>
4.文字列として入力されている値を数値に変換する。

和暦で記載されている部分を西暦に変換する。
ロジックが非常に勉強になった。
applyで定義した関数をデータフレームに適用できることもわかった。


```python
import unicodedata
import re
import datetime

# 各年号の元年を定義
eraDict = {
    "明治": 1868,
    "大正": 1912,
    "昭和": 1926,
    "平成": 1989,
    "令和": 2019,
}

def japanese_calender_converter(text):
    # テキストがNaNやNoneの場合の処理
    # テキストがNaNやNone、または文字列でない場合の処理
    if pd.isna(text) or text is None or not isinstance(text, str):
        return None
    
    # 正規化
    normalized_text = unicodedata.normalize("NFKC", text)
    
    # 年のみを抽出する正規表現
    pattern = r"(?P<era>{eraList})(?P<year>[0-9]{{1,2}}|元)年".format(eraList="|".join(eraDict.keys()))
    date = re.search(pattern, normalized_text)
    
    # 抽出できなかったら終わり
    if date is None:
        # print(f"Cannot convert {text} to western year")
        return None

    # 年を変換
    era = date.group("era")
    if date.group("year") == "元":
        year = eraDict[era]
    else:
        year = eraDict[era] + int(date.group("year")) - 1

    return year

realestate_data['建築年'] = realestate_data['建築年'].apply(japanese_calender_converter)

```

四半期などの文字を数値に変換。

```python
def convert_quarter_to_decimal(text):
    # 年と四半期を抽出
    match = re.search(r'(\d+)年第(\d)四半期', text)
    if match:
        year = int(match.group(1))
        quarter = int(match.group(2))

        # 四半期を小数点の形式に変換
        decimal = (quarter - 1) * 0.25
        return year + decimal
    else:
        return None
```

値の文字も数字に変換

ここは地道に変換していったが、値の数が多くなると取れない手段だったので
もっといい方法があるのだと思う。

```python
realestate_data.loc[realestate_data['最寄駅：距離（分）'] == '30分?60分' , '最寄駅：距離（分）'] = 45
realestate_data.loc[realestate_data['最寄駅：距離（分）'] == '1H?1H30' , '最寄駅：距離（分）'] = 75
realestate_data.loc[realestate_data['最寄駅：距離（分）'] == '1H30?2H' , '最寄駅：距離（分）'] = 105
realestate_data.loc[realestate_data['最寄駅：距離（分）'] == '2H' , '最寄駅：距離（分）'] = 120

realestate_data['最寄駅：距離（分）'] = pd.to_numeric(realestate_data['最寄駅：距離（分）'],errors='coerce')
```

<h3>
5. 欠損値の処理

勉強のついでにと２パターン試してみた。

①平均値で欠損値を埋めるパターン
中央値やランダムが良いパターンも有る。

```python
mean_value = realestate_data['最寄駅：距離（分）'].mean()
realestate_data['最寄駅：距離（分）'].fillna(mean_value, inplace=True)
```

②欠損値を削除するパターン
あんまり使うことがよくなさそうな印象。
とはいえ有効なタイミングもあると思うので、使い分けれるようにデータ理解を深める必要がある。

```python
realestate_data = realestate_data.dropna(subset=['建築年'])
```

<h3>
6. テストデータを機械学習に入れてみる。

何やら使い勝手が良いらしい、GBDTを使う。

```python
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# データの分割
X = realestate_data.drop(columns=['ID', '取引価格（総額）_log'])
y = realestate_data['取引価格（総額）_log']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# XGBoostの設定
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)

params = {
    "objective": "reg:squarederror",
    "eval_metric": "rmse",
    "booster": "gbtree"
}

# トレーニング
num_round = 100
bst = xgb.train(params, dtrain, num_round, evals=[(dtrain, 'train'), (dtest, 'eval')], early_stopping_rounds=10)

# 予測
y_pred = bst.predict(dtest)
mse = mean_squared_error(y_test, y_pred)
print(f'Mean Squared Error: {mse}')

```

<h3>
7. 提出用データでモデルから予測し、csv化して提出

結果は下記。
どれだけ悪いのかよくわかんないけど、順位は下の方。


![スクリーンショット 2023-08-08 1.38.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330320/e97d17ab-f6be-6418-45a7-8e79a62f1efb.png)

<h2>
わかったこと

・機械学習は実装するだけではだめっぽい。
・「モデルの使い分けや学習をどのように進めるか」「同じデータからどんな特徴量を見出すか」にデータ分析の能力の違いが出るのかな。

今後は分析コンペの参加の仕方やGBDTの流れを体験できたので、
次は学習を特徴量に着目してモデルを作成してみる。