kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Intermediate Machine Learning : Kaggle Courses で学びながら「住宅価格予測」コンペに参加する

Kaggle が公開している「Kaggle Courses」「Intermediate Machine Learning」コースを受講した.Kaggle のコンペティション「Housing Prices Competition for Kaggle Learn Users(住宅価格予測)」をテーマに試行錯誤をして,実際にモデルを登録することもできる.アルゴリズムとしては「ランダムフォレスト」「XGBoost」を使う.アジェンダを見るとわかる通り,データセットの前処理からモデルの構築評価まで幅広く体験できる.

www.kaggle.com

なお,前提コースである「Pandas」「Intro to Machine Learning」は既に受講していて,以下にまとめてある.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

アジェンダ 🏠

「Intermediate Machine Learning」コースには「計7種類」のレッスン(ドキュメントと演習)がある.

  1. Introduction
  2. Missing Values
  3. Categorical Variables
  4. Pipelines
  5. Cross-Validation
  6. XGBoost
  7. Data Leakage

住宅価格予測 🏠

1460 件のデータセットに 80 個の特徴量を含んでいる.その中から今回は 7 個の特徴量を使う.このあたりは前提コース「Intro to Machine Learning」と同じ.そして,特徴量の中に予測する SalePrice(住宅価格) も含まれていることから「教師あり学習(回帰)」と言える.

X_full.shape
# (1460, 80)

X.shape
# (1460, 7)

X.columns
# Index(['LotArea', 'YearBuilt', '1stFlrSF', '2ndFlrSF', 'FullBath', 'BedroomAbvGr', 'TotRmsAbvGrd'], dtype='object')

まず 1. Introduction2. Missing Values3. Categorical Variables4. Pipelines では,scikit-learnRandomForestRegressor を使って「ランダムフォレスト」でモデルを構築する.以下のように適当にパラメータを設定して比較したり(今回は model_3 の平均絶対誤差 MAE が1番低かった👌),欠損値を考慮したり,カテゴリ変数をエンコーディングしたり,一歩一歩モデル精度を向上させていく.また scikit-learnPipeline を使って,コード実装を改善する.

model_1 = RandomForestRegressor(n_estimators=50, random_state=0)
model_2 = RandomForestRegressor(n_estimators=100, random_state=0)
model_3 = RandomForestRegressor(n_estimators=100, criterion='mae', random_state=0)
model_4 = RandomForestRegressor(n_estimators=200, min_samples_split=20, random_state=0)
model_5 = RandomForestRegressor(n_estimators=100, max_depth=7, random_state=0)

実際に評価をしながら進めるため,今回は欠損値を平均値で埋めるよりも特徴量を削除した方がパフォーマンスが良いなど,予想とは違う気付きもあって良かった.

  • Missing Values(欠損値)
    • [1] A Simple Option: Drop Columns with Missing Values(単純に特徴量を削除する)
    • [2] A Better Option: Imputation(より良く平均値などで埋める)
    • [3] An Extension To Imputation(値を埋めつつ欠損値の有無を表現する新しい特徴量を追加する)
  • Categorical Variables(カテゴリ変数)
    • [1] Drop Categorical Variables(カテゴリ変数を削除する)
    • [2] Ordinal Encoding(順序エンコーディング)
    • [3] One-Hot Encoding(ワンホットエンコーディング)

実際に Kaggle コンペティションにモデルを登録して,Leaderboard で順位が上がっていくことも確認する🏆

f:id:kakku22:20211123120838p:plain

交差検証 🏠

5. Cross-Validation では,scikit-learncross_val_score() を使って「交差検証」を行う.分割数 cv35 に設定しながら最終的な平均値を確認する.

scikit-learn.org

そして「ランダムフォレスト」に設定するパラメータ n_estimators の最善値を探す.今回は n_estimators = 50, 100, 150, 200, 250, 300, 350, 400 で比較して,結果的として 200 のパフォーマンスが1番良かった.

f:id:kakku22:20211123122155p:plain

XGBoost 🏠

ここまでは「ランダムフォレスト(アンサンブル学習)」を使ってきたけど,次は「XGBoost(勾配ブースティング)」を適用する.以下のようにパラメータを変えて比較をするけど,重要なのはアルゴリズムを変えることも考えながらコンペティションに参加するという点になる.

my_model_1 = XGBRegressor(random_state=0)
# Mean Absolute Error: 17662.736729452055

my_model_2 = XGBRegressor(n_estimators=1000, learning_rate=0.05)
# Mean Absolute Error: 16688.691513270547

my_model_3 = XGBRegressor(n_estimators=1)
# Mean Absolute Error: 127895.0828807256

xgboost.readthedocs.io

Data Leakage 🏠

7. Data Leakage では,モデルに対する考察として「Data Leakage(データ漏洩)」を学ぶ.「Data Leakage」とは,トレーニングデータセットにターゲットに関する「含まれていはいけないデータが含まれていること」と言える.よって,モデルの検証時にはパフォーマンスが高くなり,本番環境にデプロイするとパフォーマンスが低くなってしまう.「Data Leakage」として,具体的には以下の2種類が載っていた.

  • Target leakage(ターゲット漏洩)
    • 例 : 肺炎予測をするときに「抗生物質を服用しているか」という特徴量を使ってしまう
      • 本来は「肺炎である」と診断されてから処方されるため,将来の予測には使えない
  • Train-Test Contamination(トレインテスト汚染)
    • 例 : データセットを前処理する場合に欠損値を平均値などで埋める場合に検証データの精度が高くなってしまう
      • 検証データを除外して前処理をする
      • scikit-learntrain_test_split() から Train-Test という名前になっている

まとめ 🏠

「Kaggle Courses」「Intermediate Machine Learning」コースを受講した.Kaggle のコンペティション「Housing Prices Competition for Kaggle Learn Users(住宅価格予測)」に参加することもできて,一般的な機械学習ワークフローを体験することができた.とても良かった👏

次は「Feature Engineering」コースと「Machine Learning Explainability」コースに進もうと思う.

f:id:kakku22:20211123123758p:plain

入門者でも挫折せずに読める!「機械学習図鑑」で "17種類" のアルゴリズムを学ぶ

「機械学習図鑑」を読んだので簡単にまとめる.正確には今年5月頃に読んでいたけど,まだ書評記事を書いてなかった📕

まず前提として,本書を読んだときには僕は機械学習に詳しくなく入門者だった.機械学習に関連する書籍を何冊か買ってみたけど,そのときの知識では理解できないことも多く,最後まで読めずに挫折することが多かった.そこで本当に入門者でも読めそうな本を探していたところ「見て試してわかる機械学習アルゴリズムの仕組み 機械学習図鑑」の評判が良さそうで読むことにした.素晴らしかった👏

対象読者

本書の冒頭に「対象読者」が載っている.以下は一部を抜粋しているけど,まさに僕だった.本書を読んだことにより,今までうまく理解できなかった書籍やウェブサイトを読めるようになり,本書を読んだ効果を感じることができた.

  • 機械学習に興味があり、勉強し始めている。
  • 数式があまり得意ではなく、機械学習の専門書を読むのに苦労している。
  • ある程度プログラミングの経験があり、サンプルコードを実行することができる。

本書の良いところは多くある.オールカラーだし,図表が多く載っているし,scikit-learn のサンプルコードも解説されている.そして「17種類」ものアルゴリズムが紹介されているのも良かった.

目次

  • 第1章「機械学習の基礎」
    • 1.1 : 機械学習の概要
    • 1.2 : 機械学習に必要なステップ
  • 第2章「教師あり学習」
    • 01 : 線形回帰
    • 02 : 正則化
    • 03 : ロジスティック回帰
    • 04 : サポートベクトルマシン
    • 05 : サポートベクトルマシン(カーネル法)
    • 06 : ナイーブベイズ
    • 07 : ランダムフォレスト
    • 08 : ニューラルネットワーク
    • 09 : kNN
  • 第3章「教師なし学習」
    • 10 : PCA
    • 11 : LSA
    • 12 : NMF
    • 13 : LDA
    • 14 : k-means 法
    • 15 : 混合ガウス分布
    • 16 : LLE
    • 17 : t-SNE
  • 第4章「評価方法および各種データの扱い」
    • 4.1 : 評価方法
    • 4.2 : 文書データの変換処理
    • 4.3 : 画像データの変換処理
  • 第5章「環境構築」
    • 5.1 : Python3 のインストール
    • 5.2 : 仮想環境
    • 5.3 : パッケージインストール

本書は今年5月に合格した「Python 3 エンジニア認定データ分析試験」の準備をするのにも非常に役立った.

kakakakakku.hatenablog.com

第1章「機械学習の基礎」

第1章では「機械学習とは?」という内容から「教師あり学習」「教師なし学習」「強化学習」の具体例までわかりやすく紹介されている.特に書籍名に「図鑑」と書いてある通り,図表が多く載っている点が素晴らしく,入門者だと単純なことでも最初はうまく理解できず悩むため,本書は本当に読みやすく書かれていると思う.

第2章「教師あり学習」

第2章では「教師あり学習」として「9種類」のアルゴリズムが紹介されている.どのアルゴリズムも基本的な考え方が図表で解説されていて,実装例は scikit-learn のサンプルコードで解説されているため,挫折することなく読み進めることができた.またサンプルコードは Jupyter Notebook 形式でダウンロードできるので,気になるところは積極的に試すようにした.

www.shoeisha.co.jp

例えば,以下は「線形回帰」scikit-learnLinearRegression で実装するサンプルコードを参考に Matplotlib を使って可視化まで試してみた.サンプルコードを動かすことに加えて自分で試行錯誤をしてみるとより理解が深まると思う.

from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt


X = [[10.0], [8.0], [13.0], [9.0], [11.0], [14.0], [6.0], [4.0], [12.0], [7.0], [5.0]]
y = [8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68]

model = LinearRegression()
model.fit(X, y) 

print(model.intercept_)
# 切片 : 3.0000909090909094

print(model.coef_)
# 傾き : 0.50009091

y_pred = model.predict([[0], [1]]) 
print(y_pred)
# x=0, x=1 に対する予測結果

y_pred_all = model.predict(X)
# X 全体に対する予測結果

plt.scatter(X, y)
plt.plot(X, y_pred_all, linewidth=0.5)
# グラフにプロット

f:id:kakku22:20211119100437p:plain

また線形回帰の解釈の難しさとして「アンスコムの例」の紹介もあったりして,関連トピックが載っている点も視野を広げる意味で良かった.

ja.wikipedia.org

第3章「教師なし学習」

第3章では「教師なし学習」として「8種類」のアルゴリズムが紹介されている.特に入門者として最初は「教師なし学習」の理解がしにくく感じたけど,実際に PCAt-SNEk-means などのサンプルコードを実際に試したりもして,基本的な考え方と scikit-learn での実装を理解できるようになった.

例えば,以下は「PCA」scikit-learn で実装するサンプルコードを参考に Matplotlib を使って「累積寄与度」の可視化まで試してみた.iris データセット(アヤメ)の特徴量4個を2個まで次元削減をした効果を確認できるようになった.

from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
import matplotlib.ticker as ticker
import numpy as np


data = load_iris()

model = PCA(n_components=2)
model = model.fit(data.data)
# 次元を 4 → 2 に削減

print(model.transform(data.data)[0:5])
# 次元削減後のデータセットの先頭を表示
# [[-2.68412563  0.31939725]
#  [-2.71414169 -0.17700123]
#  [-2.88899057 -0.14494943]
#  [-2.74534286 -0.31829898]
#  [-2.72871654  0.32675451]]

fig, ax = plt.subplots()
ax.plot(np.cumsum(np.append(0, model.explained_variance_ratio_)))
ax.grid()
# 累積寄与率をグラフにプロット

f:id:kakku22:20211119101219p:plain

第4章「評価方法および各種データの扱い」

第4章では「評価」という重要なトピックで「評価手法」「ハイパーパラメーター」「過学習」など,知っておくべき内容がわかりやすくまとまっている.特に「教師あり学習」「分類」「回帰」で使う指標は以下のように整理されていてイメージしやすく,またそれぞれの指標の使い分けなども載っていた.

  • 分類問題
    • 混合行列
    • 正解率
    • 適合率
    • 再現率
    • F 値
    • AUC (Area Under the Curve)
  • 回帰問題
    • 平均二乗誤差
    • 決定係数

そして並行して読んでいる「仕事ではじめる機械学習 第2版」「3章 : 学習結果を評価するには」を読む前提としても役立った.

まとめ

「機械学習図鑑」を読んだ.入門者として機械学習を勉強するときには欠かせない一冊なのではないかと思う.当然ながら本書を読むだけで全てに精通できるわけではないけど,今までうまく理解できなかった書籍やウェブサイトを読めるようになったことは非常に大きな効果だったし,気付きもたくさんあった.そして,著者目線だと「本当に入門者でも挫折しないで読める書籍を書く技術」に驚いた.スゴイ!今後も何度も読み直すとは思うけど,素晴らしい一冊だった👏

小学生も楽しめる!Minecraft Hour of Code でプログラミング的思考を学ぶ

今年8月頃から Minecraft に今さらドハマリをして平日深夜や週末に時間を捻出しつつプレイをしている.そして娘と一緒にやるようにもなった.ふと Minecraft をテーマにしたプログラミング的思考を学ぶコンテンツはあるのかな?と思って調べてみたら「Hour of Code」に出会った.プログラミングに限らずコンピュータサイエンスを学ぶコンテンツが多く公開されていて素晴らしかった💡

code.org

Minecraft Hour of Code

その中に Minecraft をテーマにした「Minecraft Hour of Code」がある.どれも Scratch のように「ブロック」を使ってプログラミング的思考を学ぶ仕組みになっていて,適材適所に「繰り返しブロック」「関数ブロック」などを使うことで楽しく学びを深められる.僕自身も全てクリアしたし,娘(小学校1年生)も楽しみながらすべてクリアしていた.「Hour of Code」の良さを紹介しようと思う👏

code.org

「Minecraft Hour of Code」には大きく以下の「4種類」のコンテンツがある.

  • マインクラフト: ボヤージュ アクアティック (Minecraft Voyage Aquatic)
  • マインクラフト: 主人公の旅 (Minecraft Hero’s Journey)
  • マインクラフト: アドベンチャー (Minecraft Adventurer)
  • マインクラフト: デザイナー (Minecraft Designer)

それぞれ独立したコンテンツになっているため,順番はなく,どれを選んでも良いようになっている.コンテンツの中に YouTube 動画が埋め込まれていたり,海外のマインクラフターのおもしろ動画が埋め込まれていたり,楽しめる要素が多くある.Minecraft 的にも,羊毛をハサミで刈ったり,トロッコに乗ったり,マグマを丸石で埋めたり,コンジットを作ったり,クリーパーから逃げたり,どれもワクワクする!

キャラクターを選択しよう!

どのコンテンツも最初はキャラクターを選択する.Steve と Alex!

f:id:kakku22:20211108142437p:plain

「ブロック」を使おう!

最初は「マインクラフト: ボヤージュ アクアティック」を例にする.基本的には Scratch のように「ブロック」を使ってゴールを目指すことになり,以下の例は「前にすすむ」を使って「チェスト」を目指す.結果的には2歩進めば OK!難易度や操作には多少の違いがある.

f:id:kakku22:20211108142606p:plain

「リピート」を使おう!

3問目と4問目に進むと「リピート : while」という概念の必要性を体験できるようになっている.3問目では「タラ」を目指して7歩進む.さすがに「7歩」だと多すぎるし,具体的な歩数を考えなくても良いような表現があると便利で,4問目では「イルカ」を目指して「ゴールまでリピート」を使う.このように最初から「リピート : while」を教えるのではなく,必要性を体験して「気付かせる」ストーリーになっている.

f:id:kakku22:20211108143114p:plain

f:id:kakku22:20211108143127p:plain

「リピート」と「条件」を組み合わせよう!

「マインクラフト: ボヤージュ アクアティック」の11問目まで進むと比較的複雑になってくるけど,Minecraft ではよく知られた「コンジット」を作る.ポイントは「シーランタン」の上で方向転換をするために「条件 : if」という概念を組み合わせるところ.ここまで理解できると複雑な動きも作れるようになる.

f:id:kakku22:20211108144113p:plain

「繰り返し」と「条件」を組み合わせよう!

今度は「マインクラフト: アドベンチャー」を例にする.他のコンテンツにも「繰り返し : for」という概念は出てくるけど,特に「アドベンチャー」では Minecraft でよくある操作を試せるので楽しめる.11問目は洞窟でブランチマイニングをしているときに「マグマダイブしないように丸石を置く」という操作で「繰り返し : for」「条件 : if」を組み合わせる.じっくり考えながらトライアンドエラーを楽しめる!

f:id:kakku22:20211108145118p:plain

「関数」を使おう!

「マインクラフト: 主人公の旅」の8問目からは「関数 : function」という概念が出てくる.以下はネザーに橋をかけて「本」を目指すために,関数として用意された「短い橋をかける」「長い橋をかける」ブロックを使う.このように再利用性という観点でも「気付かせる」ストーリーになっている.

f:id:kakku22:20211108145721p:plain

「イベント」を使おう!

「マインクラフト: デザイナー」は少し高度なトピックを学ぶコンテンツになり,途中から「イベント : event」という概念が出てくる.「夜になったらときにスポーンする」「ゾンビが出現したらプレイヤーをに向かって歩く」「牛を使用したらミルクを落とす」など,実際に Minecraft の中でも使われている操作となり,Minecraft で言う Mob の動きを実装するという点で「視野が広がる」ストーリーになっている.娘に聞いたところ「イベント」だけは少し難しかったと言っていた.

f:id:kakku22:20211108150742p:plain

以下は「マインクラフト: デザイナー」の途中で視聴する YouTube 動画で「イベント」が紹介されている.

youtu.be

まとめ

Minecraft をテーマにしたプログラミング的思考を学ぶコンテンツを調べてみたら「Hour of Code」に出会った.「Minecraft Hour of Code」は非常によく考えられたストーリーになっていて,誰でも楽しめるコンテンツだった.その中でも代表的な点を紹介したけど,是非「4種類」のコンテンツを全て試してみると良いと思う!

また娘などに Scratch を教える機会もあるけど,使えるブロックが多いため可能性が多すぎて逆に何も作れないということがある.「Minecraft Hour of Code」だと,最初から明確なゴールがあるため,与えられたブロックを使えばよく「パズル感覚」楽しめるのが良さそうだった.Scratch を試す前に試すとより効果的なのかもしれない!

「Hour of Code」には他にも多くコンテンツがあるので試していくぞー💪

code.org

imbalanced-learn の SMOTE モジュールを使って簡単にオーバーサンプリングを実現する

分類などの機械学習モデルを構築するときにデータセットに偏り(不均衡データ)があると適切に学習できない可能性がある.データセットを強制的に増やす操作を「オーバーサンプリング」と言って,SMOTE (Synthetic Minority Over-sampling Technique)ADASYN (Adaptive Synthetic) など,具体的な「オーバーサンプリング手法」がよく知られている.ちなみに SMOTEk-NN (k-Nearest Neighbor) : k近傍法 を参考に近接データを増やす.

imbalanced-learn とは

今回紹介する imbalanced-learn「不均衡データ」を扱うライブラリで「オーバーサンプリング」「アンダーサンプリング」などを簡単に実装できる.そして scikit-learn と互換がある.また GitHub だと scikit-learn-contrib プロジェクトで管理されている.

github.com

SMOTE モジュールを試す

今回は imbalanced-learn に入門するために SMOTE モジュールを試す.Over-sampling のドキュメントに載っているサンプルコードを参考にしつつ,もっと簡単に書き直してみた.

まず,scikit-learnmake_classification() 関数を使って,2000 データセットを 0.05 : 0.95 の割合で不均衡データとして生成した.特徴量はシンプルに2個にした.そして imbalanced-learnSMOTE モジュールで fit_resample() 関数を使うと簡単に「オーバーサンプリング」をすることができる.

from imblearn import FunctionSampler
from imblearn.over_sampling import SMOTE
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt

def plot_resampling(X, y, sampler, ax):
    X_res, y_res = sampler.fit_resample(X, y)
    ax.scatter(X_res[:, 0], X_res[:, 1], c=y_res, alpha=0.8, edgecolor="k")
    title = f"Resampling with {sampler.__class__.__name__}"
    ax.set_title(title)

X, y = make_classification(
    n_samples=2000,
    n_features=2,
    n_informative=2,
    n_redundant=0,
    n_classes=2,
    weights=[0.05, 0.95],
    class_sep=1.0,
    random_state=1
)

fig, axs = plt.subplots(nrows=2, ncols=1, figsize=(20, 20))

samplers = [
    FunctionSampler(),
    SMOTE()
]

for ax, sampler in zip(axs.ravel(), samplers):
    plot_resampling(X, y, sampler, ax)

そして matplotlibscatter() 関数で散布図を描画した.Resampling with FunctionSampler(通常)Resampling with SMOTE(オーバーサンプリング) を比較すると,特徴量(紫色)に大きく差を確認できる.便利だ!

f:id:kakku22:20211101135838p:plain

関連記事

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

iris データセットを libsvm フォーマットにする : scikit-learn の dump_svmlight_file()

scikit-learndatasets モジュールの中に libsvm フォーマットのデータセットを扱う関数がある.libsvm フォーマットは以下のフォーマットでデータセットを表現し,1番左にラベル(教師データ)を持つ.例えば Amazon SageMaker の組み込みアルゴリズム XGBoost でもサポートされている.

<label> <index1>:<value1> <index2>:<value2> ...

以下のサイトには libsvm フォーマットで多種多様なデータセットが公開されている.

www.csie.ntu.edu.tw

libsvm フォーマット例

例えば iris データセット(アヤメ)に以下のサンプルデータセットがあったとする.Label は3種類ある.

  • 0 = setosa(ヒオウギアヤメ)
  • 1 = versicolor(ハナショウブ)
  • 2 = virginica(カキツバタ)
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) Label
5.1 3.5 1.4 0.2 0
4.9 3.0 1.4 0.2 0
4.7 3.2 1.3 0.2 0

サンプルデータセットを libsvm フォーマットにすると以下となる.

0 0:5.1 1:3.5 2:1.4 3:0.2
0 0:4.9 1:3 2:1.4 3:0.2
0 0:4.7 1:3.2 2:1.3 3:0.2

scikit-learn dump_svmlight_file() 関数

scikit-learn を使って簡単に iris データセット(アヤメ)をセットアップできるため「特徴量」「ラベル」を取得して,同じく scikit-learndump_svmlight_file() 関数をさっそく試す.最終的に iris-libsvm ファイルに書き出す.コードはシンプルに書ける!

from sklearn.datasets import dump_svmlight_file
from sklearn.datasets import load_iris

iris = load_iris()

# 特徴量
x = iris.data

# ラベル
y = iris.target

dump_svmlight_file(x, y, 'iris-libsvm')

scikit-learn.org

実行後に head -n 50 iris-libsvm コマンドを実行して書き出した iris-libsvm ファイルを確認すると,期待通りに libsvm フォーマットになっていた.

0 0:5.1 1:3.5 2:1.4 3:0.2
0 0:4.9 1:3 2:1.4 3:0.2
0 0:4.7 1:3.2 2:1.3 3:0.2
0 0:4.6 1:3.1 2:1.5 3:0.2
0 0:5 1:3.6 2:1.4 3:0.2
0 0:5.4 1:3.9 2:1.7 3:0.4
0 0:4.6 1:3.4 2:1.4 3:0.3
0 0:5 1:3.4 2:1.5 3:0.2
0 0:4.4 1:2.9 2:1.4 3:0.2
0 0:4.9 1:3.1 2:1.5 3:0.1
0 0:5.4 1:3.7 2:1.5 3:0.2
0 0:4.8 1:3.4 2:1.6 3:0.2
0 0:4.8 1:3 2:1.4 3:0.1
0 0:4.3 1:3 2:1.1 3:0.1
0 0:5.8 1:4 2:1.2 3:0.2
0 0:5.7 1:4.4 2:1.5 3:0.4
0 0:5.4 1:3.9 2:1.3 3:0.4
0 0:5.1 1:3.5 2:1.4 3:0.3
0 0:5.7 1:3.8 2:1.7 3:0.3
0 0:5.1 1:3.8 2:1.5 3:0.3
0 0:5.4 1:3.4 2:1.7 3:0.2
0 0:5.1 1:3.7 2:1.5 3:0.4
0 0:4.6 1:3.6 2:1 3:0.2
0 0:5.1 1:3.3 2:1.7 3:0.5
0 0:4.8 1:3.4 2:1.9 3:0.2
0 0:5 1:3 2:1.6 3:0.2
0 0:5 1:3.4 2:1.6 3:0.4
0 0:5.2 1:3.5 2:1.5 3:0.2
0 0:5.2 1:3.4 2:1.4 3:0.2
0 0:4.7 1:3.2 2:1.6 3:0.2
0 0:4.8 1:3.1 2:1.6 3:0.2
0 0:5.4 1:3.4 2:1.5 3:0.4
0 0:5.2 1:4.1 2:1.5 3:0.1
0 0:5.5 1:4.2 2:1.4 3:0.2
0 0:4.9 1:3.1 2:1.5 3:0.2
0 0:5 1:3.2 2:1.2 3:0.2
0 0:5.5 1:3.5 2:1.3 3:0.2
0 0:4.9 1:3.6 2:1.4 3:0.1
0 0:4.4 1:3 2:1.3 3:0.2
0 0:5.1 1:3.4 2:1.5 3:0.2
0 0:5 1:3.5 2:1.3 3:0.3
0 0:4.5 1:2.3 2:1.3 3:0.3
0 0:4.4 1:3.2 2:1.3 3:0.2
0 0:5 1:3.5 2:1.6 3:0.6
0 0:5.1 1:3.8 2:1.9 3:0.4
0 0:4.8 1:3 2:1.4 3:0.3
0 0:5.1 1:3.8 2:1.6 3:0.2
0 0:4.6 1:3.2 2:1.4 3:0.2
0 0:5.3 1:3.7 2:1.5 3:0.2
0 0:5 1:3.3 2:1.4 3:0.2

関連記事

kakakakakku.hatenablog.com