プログラミング演習・14章版 第14章 数値計算・可視化・機械学習
教材コード

数値計算・可視化・機械学習

データの表を作るだけでは結論は出ません.数値を正しく計算し,適切な図で確かめ,予測を作るなら未使用のデータで評価します.この章では標準ライブラリの math に加え,NumPy,pandas,matplotlib,scikit-learn を導入します.後の四つは環境に別途インストールが必要です.

数値計算から評価までの分析の流れ

math と数値計算

知識

モジュール(module)は関連する機能をまとめた Python ファイルです.import math によって math.sqrt などを呼べる.平方根は「二乗すると元の数になる非負の値」であり,math.sqrt(16) は 4.0 を返します.

身近な例として,工具箱に「平方根を計算する道具」が入っていると考えよう.import math は工具箱を机に置く操作,math.sqrt(16) はその道具に16を渡す操作です.

module は「一つのまとまり」で,関連語は library(ライブラリ,機能の集まり)です.発表では “We import the math module” といいます.

そのまま演習知識 · そのまま演習
chapter-14_code_1.py
import math
print(math.sqrt(16))
print(math.sqrt(2) ** 2)
ヒントを見る

演算子の優先順位と、変数に今保存されている値を順に確認します。代入による更新は、その行よりあとに使う値へ反映されます。

演習の解説を見る

一行目の結果は 4.0.二行目は浮動小数点の丸めのため数学上の 2 と実際の表示がぴったり一致するとは限りません.実行環境で値を確認します.

虫食い知識 · 虫食い
chapter-14_code_2.py
import math
print(math.___(25))
ヒントを見る

25の平方根を求める数学モジュールの関数です。2乗する計算と逆の関係になる操作を選びます。

演習の解説を見る

sqrt を補います.結果は 5.0 です.

結果の読み方と間違い

import math はモジュールを使える状態にし,math.sqrt(16) が平方根を計算します.出力は整数の4ではなく浮動小数点数の 4.0 です.

式 意味
16 ** 2 16の二乗
math.sqrt(16) 16の平方根
math.sqrt(2) ** 2 近似値を二乗した結果

sqrt(16) だけでは,sqrt を直接読み込んでいないので名前が見つかりません.import math と書いたら math.sqrt(16) と呼ぶ.

NumPy の配列

知識

配列(array)は同種の値をまとまった形で扱う.NumPy の ndarray では a + 10 が各要素に10を加える.通常の Python リストの + はリスト同士の連結であり,意味が異なります.二次元配列の sum(axis=1) は行ごとの和です.

身近な例として,点数が三人分あるとき,「全員に10点を足す」という同じ計算をまとめて書けます.二次元配列は表と考えればよいでしょう.axis=1 では横一行の数をそれぞれ足します.

配列の演算と行方向の集計
配列の演算と行方向の集計

array は「整列したもの」を指し,関連語は dimension(次元)と axis(軸)です.発表では “Add ten to every element of the array” といいます.

そのまま演習知識 · そのまま演習
chapter-14_code_3.py
import numpy as np
a = np.array([1, 2, 3])
print(a + 10)
b = np.array([[1, 2], [3, 4]])
print(b.sum(axis=1))
ヒントを見る

このコードでは a、b の値を追ってください。配列の形と、計算する軸を区別します。axis=0 は同じ列、axis=1 は同じ行の値をまとめるので、対象の値を書き並べて確認します。

演習の解説を見る

最初は三要素それぞれに10を足します.二つ目は第一行の 1 + 2 = 3 と第二行の 3 + 4 = 7 を返します.

実行結果の例
[11 12 13]
[3 7]
虫食い知識 · 虫食い
chapter-14_code_5.py
import numpy as np
a = np.___([1, 2, 3])
print(a * 2)
ヒントを見る

PythonのリストをNumPyの配列へ変換します。すると後の2倍が各要素へ作用し、リストの繰り返しにはなりません。

演習の解説を見る

array を補います.表示は [2 4 6] です.Python リストに整数を掛ける場合はリストの反復になり,計算の意味が違う.

リストとの結果の違い

a = np.array([1, 2, 3]) は三要素の NumPy 配列を作ります.a + 10 では各要素に同じ数を足すので [11 12 13] となります.a * 2 では各要素を二倍し [2 4 6] となります.

値と操作 結果
[1, 2] + [3, 4] リストを連結して四要素にします.
np.array([1, 2]) + 10 各要素に10を足します.
np.array([1, 2]) * 2 各要素を二倍します.

[1, 2, 3] + 10 はリストと整数を足そうとして TypeError になります.NumPy 配列へ変換してから要素ごとの計算を行います.また表示にカンマがない [11 12 13] は NumPy 配列の表示です.

配列の形と集計の方向

知識

二次元配列の shape は行数と列数の組です.axis=0 は行の方向をまとめ,列ごとの結果を返します.axis=1 は列の方向をまとめ,行ごとの結果を返します.結果の個数まで予想すると混同を防げる.

身近な例として,二行二列の表なら,縦に足すと列ごとに二つの答え,横に足すと行ごとに二つの答えが出ます.axis=0 は縦,axis=1 は横と実際の表に矢印を書いて確認しましょう.

shape は「形」,axis は「軸」です.関連語は row(行)と column(列)です.発表では “We sum along axis zero” といいます.

そのまま演習知識 · そのまま演習
chapter-14_code_6.py
import numpy as np
a = np.array([[1, 2], [3, 4]])
print(a.shape)
print(a.sum(axis=0))
print(a.sum(axis=1))
ヒントを見る

このコードでは a の値を追ってください。配列の形と、計算する軸を区別します。axis=0 は同じ列、axis=1 は同じ行の値をまとめるので、対象の値を書き並べて確認します。

演習の解説を見る

形は二行二列で (2, 2) です.縦の和は 1 + 3 = 4 と 2 + 4 = 6,横の和は 1 + 2 = 3 と 3 + 4 = 7 になります.

実行結果の例
(2, 2)
[4 6]
[3 7]
虫食い知識 · 虫食い
chapter-14_code_8.py
print(a.sum(axis=___))  # column totals
ヒントを見る

列ごとの合計では、各列の値を縦方向にまとめます。行ごとの合計にする軸とは区別してください。

演習の解説を見る

0 を補います.列ごとの和は二つの値 [4 6] です.

axis を一つずつ追う

演習の a は一行目が1と2,二行目が3と4の二行二列です.a.shape は (2, 2) です.sum(axis=0) は最初の列の1と3,次の列の2と4をそれぞれ足し,[4 6] を返します.sum(axis=1) は最初の行の1と2,次の行の3と4を足し,[3 7] を返します.

指定 足す組 出力
axis=0 (1, 3) と (2, 4) [4 6]
axis=1 (1, 2) と (3, 4) [3 7]

「0は行,1は列」とだけ暗記すると,出力が列単位か行単位かを逆にしやすい.axis=0 は行の方向を縮めるため列ごとの結果が残る.実際の小さな配列で足し算を書き出して確かめる.

pandas の表と集計

知識

データフレーム(DataFrame)は列名と行を持つ表です.列を df['score'] で選び,mean() で平均を求めます.groupby('class') はクラス別に行を分け,その後の集計を各群へ適用します.欠損値,数値列の型,空の群は結果に影響するので確認します.

身近な例として,表計算ソフトの一列を選ぶ操作が df['score'] です.クラス名で行を束ねてから,束ごとに平均点を出すのが groupby です.全員の平均とクラス別の平均では,答える問いが違う.

groupby による集計の流れ
groupby による集計の流れ

frame は「枠組み」,group by は「〜によってグループ分けする」です.関連語は Series(一列のデータ)と aggregate(集計)です.発表では “We group the rows by class” といいます.

そのまま演習知識 · そのまま演習
chapter-14_code_9.py
import pandas as pd
df = pd.DataFrame({
    'class': ['A', 'A', 'B'],
    'score': [70, 90, 80]
})
print(df['score'].mean())
print(df.groupby('class')['score'].mean())
ヒントを見る

このコードでは df の値を追ってください。点数列を選んでから、グループ分けや平均を求めます。追加するデータがどのグループの件数と合計を変えるかを確かめます。

演習の解説を見る

全体の平均は (70 + 90 + 80)/3 = 80 です.A組は (70 + 90)/2 = 80,B組は一件なので80です.この例では偶然同じだが,一般には全体と各群の平均は異なります.

虫食い知識 · 虫食い
chapter-14_code_10.py
print(df['score'].___())
print(df.___('class')['score'].mean())
ヒントを見る

最初は点数列の平均、次はクラスごとに分ける操作です。二つの空欄は異なるメソッド名になります。

演習の解説を見る

順に mean,groupby です.平均の分母がどの行数かを常に確かめる.

表のどの部分を選ぶか

pd.DataFrame(...) は辞書の各キーを列名にします.演習では class 列がA,A,B,score 列が70,90,80となります.df['score'] は点数列だけを選ぶ.mean() は 70 + 90 + 80 = 240 を三件で割るため80です.groupby('class') はAの二件とBの一件に分けてから平均します.

式 答えている問い
df['score'].mean() 全体の平均はいくつか.
df.groupby('class')['score'].mean() 各クラスの平均はいくつか.

groupby を呼んだだけでは平均はまだ計算されません.どの列をどう集計するか,['score'].mean() まで指定します.点数が文字列として読み込まれた場合は数値型への変換も確認します.

表の絞り込みと欠損値

知識

df['score'] >= 70 は各行に対応する真偽値の列を作ります.これを df[...] に渡すと,真の行だけを抽出できます.欠損値(missing value)は値が記録されていない状態で,平均の分母や行数を考える前に扱いを決める必要があります.

身近な例として,名簿で「70点以上」に丸を付け,丸の付いた行だけ残す作業が絞り込みです.未記入の点数は0点とは違う.未記入をどう扱うか決めずに平均を出すと問いが変わってしまう.

missing は「欠けている」という意味で,関連語は NaN と filter(絞り込み)です.発表では “We filter rows with scores of at least seventy” といいます.

そのまま演習知識 · そのまま演習
chapter-14_code_11.py
import pandas as pd
df = pd.DataFrame({'score': [60, 80, 90]})
print(df[df['score'] >= 70])
ヒントを見る

このコードでは df の値を追ってください。点数列を選んでから、グループ分けや平均を求めます。追加するデータがどのグループの件数と合計を変えるかを確かめます。

演習の解説を見る

条件は順に偽,真,真です.したがって80点と90点の行だけ残り,元の行番号1と2が表示されます.

虫食い知識 · 虫食い
chapter-14_code_12.py
passed = df[df['score'] ___ 70]
ヒントを見る

70点ちょうども合格者として残します。境界の70を含む比較演算子を選びます。

演習の解説を見る

>= を補います.> では70点ちょうどの人が除外されます.

条件が選ぶ行

df['score'] >= 70 は順に False,True,True を作ります.df[...] はこの真偽値に対応する行を残すので,80点と90点だけになります.元の行番号は1と2のままです.

元の行番号 点数 残るか
0 60 いいえ
1 80 はい
2 90 はい

欠損値が一件あれば,単純な平均の分母を全行数と決めつけません.pandas の平均は通常,欠損値を除いた値で計算します.何件を使ったかは count() で確認できます.

df['score' >= 70] は括弧の位置が違い,列を選ぶ前に文字列と数値を比較しようとします.正しくは df[df['score'] >= 70] と書きます.外側の角括弧は行の抽出,内側は列の選択です.

グラフでデータを確かめる

知識

可視化(visualization)は値を図として表し,差や関係を読み取る助けとします.時系列の変化には折れ線,カテゴリごとの比較には棒,二数値間の関係には散布図が適します.横軸と縦軸の意味・単位を明記し,見た目の印象を元データで検証します.

身近な例として,日ごとの気温なら点を順につないで変化を追える.学部ごとの人数なら棒の高さを比べやすい.身長と体重のように二つの数字の組を並べるなら点を散らして描く.目的ごとに図を選ぶ.

visualization は visible(見える)に由来します.関連語は line chart,bar chart,scatter plot です.発表では “The horizontal axis shows days” といいます.

データの問いに応じて図を選ぶ
グラフを読み取るための白紙図
読み取りを記したグラフ
そのまま演習知識 · そのまま演習
chapter-14_code_13.py
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [2, 4, 3])
plt.xlabel('day')
plt.ylabel('value')
plt.show()
ヒントを見る

横軸と縦軸のデータは同じ位置の値どうしを組にします。変更した要素がどの点の座標を変えるかを確認してください。

演習の解説を見る

一日目から三日目までの値は順に 2, 4, 3 です.二日目が最大で,三日目に下がる.plt.xlabel と plt.ylabel は軸の意味を書きます.実データであれば value を実際の量と単位に置き換える.

虫食い知識 · 虫食い
chapter-14_code_14.py
plt.___([1, 2], [3, 4])
plt.xlabel('day')
plt.ylabel('score')
plt.show()
ヒントを見る

横と縦の値の組を点として描く散布図です。点を線で結ぶ折れ線図との違いを確認します。

演習の解説を見る

plot を補います.これは二点をつなぐ折れ線です.show() は描画を表示します.

一行ずつ図を読む

plt.plot([1, 2, 3], [2, 4, 3]) は横軸の1,2,3と縦軸の2,4,3を同じ位置どうしで組にします.つまり (1, 2),(2, 4),(3, 3) の三点を描き,順に結ぶ.xlabel と ylabel で軸名を付け,show() で表示します.

図 読み取りたいこと
折れ線 時間など順序に沿った変化
棒 カテゴリ間の大きさの比較
散布図 二つの数値の組の関係

横軸と縦軸のリストで要素数が違えば対応する点を描けません.三点なら両方三要素にします.またグラフの形だけから因果関係があるとは結論しません.

散布図・棒グラフと対話型の図

知識

散布図は二変数の観測値を点で表します.棒グラフはカテゴリ別の値を比較します.Bokeh はブラウザ上で拡大や移動ができる図を作るライブラリです.同じ値でも目的に応じて図の種類を選ぶ.

身近な例として,身長と体重を一人一つの点で示すなら散布図,学科ごとの人数なら棒グラフが読みやすい.Bokeh の図は紙に印刷する図と異なり,画面上で拡大して細部を見られます.

scatter は「散らす」,bar は「棒」,interactive は「操作に反応する」の意味です.関連語は plot(図に描く)です.発表では “The scatter plot shows paired measurements” といいます.

そのまま演習知識 · そのまま演習
chapter-14_code_15.py
from bokeh.plotting import figure, show

p = figure(title='sample')
p.scatter([1, 2, 3], [2, 1, 3])
show(p)
ヒントを見る

このコードでは p の値を追ってください。横軸と縦軸のデータは同じ位置の値どうしを組にします。変更した要素がどの点の座標を変えるかを確認してください。

演習の解説を見る

三組の座標 (1, 2),(2, 1),(3, 3) に点を置く.Bokeh を導入した環境ではブラウザに図が開きます.二つの数の組が関係しているかを見る図であり,順番に線を結ぶ必要はありません.

虫食い知識 · 虫食い
chapter-14_code_16.py
p = figure()
p.___([1, 2], [3, 4])
show(p)
ヒントを見る

Bokehの figure に、二組の座標を丸い点として加えます。点の形を表す描画メソッドを確認します。

演習の解説を見る

scatter を補います.bar はカテゴリ比較に適する別の図です.

散布図の点を確認する

p = figure(...) で図の入れ物を作り,p.scatter(...) で座標の組を描く.一番目どうしで (1, 2),二番目どうしで (2, 1),三番目どうしで (3, 3) です.show(p) がブラウザで図を開きます.

道具 例における役割
matplotlib 静的な図を手早く描く.
Bokeh ブラウザで操作できる図を描く.

p.scatter([1, 2, 3], [2, 1]) では横と縦の個数が違う.同じ観測数だけ値を用意します.棒グラフは二数値間の関係より,カテゴリ別の比較に使います.

分類・回帰・クラスタリング

知識

分類(classification)はラベルのようなカテゴリを予測します.回帰(regression)は連続的な数値を予測します.クラスタリング(clustering)は正解ラベルを使わず似たデータをまとめる.分類と回帰は教師あり学習,クラスタリングは教師なし学習の代表例です.

身近な例として,メールが迷惑メールかどうかは二種類から選ぶ分類,明日の気温を何度か予測するのは回帰です.まだ名前を付けていない曲を似た雰囲気で集めるのがクラスタリングです.「予測する答えが最初からあるか」が大きな違いです.

機械学習の問題の種類
機械学習の問題の種類

classification は class(類),regression は「戻る」,cluster は「房・集まり」に由来します.発表では “Classification predicts a category; regression predicts a number” といいます.

そのまま演習知識 · そのまま演習

次のコードを実行し,問いと方法の対応を確かめよ.

chapter-14_code_17.py
tasks = [
    ("合否を予測する", "分類"),
    ("来月の売上額を予測する", "回帰"),
    ("似た商品をまとめる", "クラスタリング"),
]
for name, method in tasks:
    print(name, method)
ヒントを見る

このコードでは tasks の値を追ってください。演算子の優先順位と、変数に今保存されている値を順に確認します。代入による更新は、その行よりあとに使う値へ反映されます。

演習の解説を見る

順に分類,回帰,クラスタリングです.合否は二つのカテゴリ,売上額は数値,似た商品の集まりには既知の正解ラベルがありません.

虫食い知識 · 虫食い

出力が「迷惑メールかどうか 分類」「翌日の降水量 回帰」の2行になるよう,空欄を埋めて実行せよ.

chapter-14_code_18.py
tasks = [
    ("迷惑メールかどうか", "___"),
    ("翌日の降水量", "___"),
]
for name, method in tasks:
    print(name, method)
ヒントを見る

メールかどうかは種類の判定、降水量は連続的な数値の予測です。予測したい結果の型から二つの方法を区別します。

演習の解説を見る

上から 分類,回帰 を入れます.降水量を「降る/降らない」に変えれば,問いが分類に変わります.

何を予測するかで選ぶ

入力が同じでも予測したい答えの形によって課題が変わります.例えば気温そのものを数値で予測するなら回帰,30度以上かどうかだけを予測するなら分類です.正解を与えず,似た気象の記録を集めるならクラスタリングです.

方法 正解ラベル 出力
分類 使う カテゴリ
回帰 使う 数値
クラスタリング 使わない 似たものの群

クラスタリングが付けた0や1という番号を,既知の正解ラベルと混同しません.番号は群を区別するための仮の名であり,群の意味はデータを確かめて解釈します.

訓練用と評価用を分ける

知識

学習データ(training data)はモデルを作るために使い,評価データ(test data)は完成後の性能を確かめるために残す.同じデータで学習と評価をすると,未知の例にも通用するか分かりません.分割前の前処理から評価データの情報が学習側に漏れることも避ける.

身近な例として,練習問題と同じ問題だけを試験に出すと,本当に応用できるか測れません.初めて見る問題を別に取っておき,練習が終わってから解く.機械学習でも同じです.

学習用と評価用の分割
学習用と評価用の分割

training は「訓練」,test は「試験」です.関連語は overfitting(過学習)と data leakage(情報漏洩)です.発表では “We evaluate on held-out data” といいます.

そのまま演習知識 · そのまま演習
chapter-14_code_19.py
from sklearn.model_selection import train_test_split

X = [[1], [2], [3], [4]]
y = [0, 0, 1, 1]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, random_state=0
)
print(len(X_train), len(X_test))
ヒントを見る

このコードでは X、y の値を追ってください。訓練用と評価用のデータは別に使います。対応する説明変数と正解ラベルが同じ組で分割されること、件数の合計が元と等しいことを確認します。

演習の解説を見る

既定では全体の四分の一を評価用にするため,四件なら学習用三件,評価用一件になります.random_state=0 は分割の再現性を保つ.ただし評価が一件だけでは性能の推定が大きくぶれるので,この例は分割操作の確認用です.

実行結果の例
3 1
虫食い知識 · 虫食い
chapter-14_code_21.py
from sklearn.model_selection import ___
X_train, X_test, y_train, y_test = train_test_split(
    [[1], [2], [3], [4]], [0, 0, 1, 1], random_state=0
)
ヒントを見る

次の行で呼んでいる、訓練用と評価用にデータを分ける関数を読み込みます。import の名前と呼び出しの名前をそろえます。

演習の解説を見る

train_test_split を補います.X は入力,y は正解を表す慣例的な名前です.

四件の分割を追う

X は入力が四件,y はそれぞれに対応する正解が四件です.train_test_split は対応関係を保ったまま,学習用と評価用に分ける.この例の既定の分割では学習用三件,評価用一件となります.

変数 使い道
X_train,y_train モデルを作るために使います.
X_test,y_test 作った後に性能を確かめる.

評価用の一件を使ってモデルの設定を何度も変え,最良の結果を選ぶと,その一件に合わせ込んでしまう.評価用は最後の確認に残す.この四件の例から性能の良し悪しを一般化しません.

図で理解する

数値分析の流れ
数値分析の流れ
機械学習の評価
機械学習の評価
学習結果を評価する:考える前
学習結果を評価する:考える前
学習結果を評価する:書き込んだ後
学習結果を評価する:書き込んだ後

練習して確かめる

数値と計算の広がり

知識

整数と小数は /、//、%、** などで計算できます。優先順位を明示したいときは括弧を使います。math モジュールには平方根などの関数があります。

chapter-14_code_22.py
import math
print(7 // 3, 7 % 3, math.sqrt(9))
そのまま演習数値と計算の広がり · そのまま演習

既存の行に続け、8//3・8%3・sqrt(16) をこの順で1行に表示してください。

ヒントを見る

追加する行でも、整数の商、余り、平方根の順に計算します。元の表示を残し、新しい結果は次の行へ出します。

演習の解説

7//3 は 2、7%3 は 1、sqrt(9) は 3.0 になります。

虫食い数値と計算の広がり · 虫食い

空欄を埋め、コードを実行してください。

chapter-14_code_23.py
import math
print(math.___(16))
ヒントを見る

16を2乗して得る値ではなく、2乗すると16になる非負の数を返す数学関数を使います。

虫食いの解説
chapter-14_code_24.py
import math
print(math.sqrt(16))

sqrt を補います。結果は 4.0。

NumPy の配列

知識

NumPy 配列は数値の集まりに要素ごとの計算をまとめて適用できます。リストの + は連結だが、配列の + は要素ごとの加算になります。

chapter-14_code_25.py
import numpy as np
a = np.array([1, 2, 3])
print(a + 10)
そのまま演習NumPy の配列 · そのまま演習

例を実行し、a * 2 の結果を予測します。

ヒントを見る

NumPyの配列では掛け算が各要素に作用します。Pythonのリストを2回繰り返す場合とは結果が異なります。

演習の解説

各要素に2を掛けるので [2 4 6]。

虫食いNumPy の配列 · 虫食い

空欄を埋め、コードを実行してください。

chapter-14_code_26.py
import numpy as np
a = np.___([1, 2, 3])
ヒントを見る

NumPyの配列をリストから作る関数です。リストの要素を保持した配列として a に代入します。

虫食いの解説
chapter-14_code_27.py
import numpy as np
a = np.array([1, 2, 3])

array を補います。NumPy の導入が必要。

配列の形と集計

知識

NumPy 配列には shape があり、2次元配列では行と列を指定して要素を読みます。axis=0 は列ごと、axis=1 は行ごとの集計になります。

chapter-14_code_28.py
import numpy as np
a = np.array([[1, 2], [3, 4]])
print(a.shape, a.sum(axis=0))
そのまま演習配列の形と集計 · そのまま演習

axis=1 に変えて結果を比べます。

ヒントを見る

axis を変えると、同じ行の値をまとめる計算になります。配列の形は変わらず、集計する方向だけが変わります。

演習の解説

列ごとの和は [4,6]、行ごとの和は [3,7]。

虫食い配列の形と集計 · 虫食い

配列 a の定義は残します。axis の空欄を埋めて列ごとの合計を求め、1列目の1と3、2列目の2と4をそれぞれ足した配列 [4 6] を1行で表示してください。

chapter-14_code_29.py
import numpy as np
a = np.array([[1, 2], [3, 4]])
print(a.sum(axis=___))
ヒントを見る

問題で指定された列の合計になるように軸を選びます。配列の形を書き、同じ列の二つの値を対応させます。

虫食いの解説
chapter-14_code_30.py
import numpy as np
a = np.array([[1, 2], [3, 4]])
print(a.sum(axis=0))

0 を補います。

pandas の表データ

知識

pandas の DataFrame は列名付きの表を表します。CSVを読み込んで列を選び、平均などの集計を行える。欠損値や型にも注意します。

chapter-14_code_31.py
import pandas as pd
df = pd.DataFrame({'score': [70, 90]})
print(df['score'].mean())
そのまま演習pandas の表データ · そのまま演習

点数100を3件目に追加して平均を表示してください。

ヒントを見る

3件目を追加したあとは、合計だけでなく平均の分母も3になります。点数列から平均を計算する行は残します。

演習の解説

列の mean は数値列の平均を返します。

虫食いpandas の表データ · 虫食い

空欄を埋め、コードを実行してください。

chapter-14_code_32.py
import pandas as pd
df = pd.DataFrame({'score': [70, 90]})
print(df['score'].___())
ヒントを見る

点数の合計だけではなく、件数で割った平均を求めるメソッドです。列を選ぶ処理は既に書かれています。

虫食いの解説
chapter-14_code_33.py
import pandas as pd
df = pd.DataFrame({'score': [70, 90]})
print(df['score'].mean())

mean を補います。pandas の導入が必要。

pandas の絞り込みとグループ化

知識

表の条件抽出は真偽値の列を使います。groupby でカテゴリ別に集計できます。欠損値がある列は集計方法を決めてから扱う。

chapter-14_code_34.py
import pandas as pd
df = pd.DataFrame({'group':['A','A','B'], 'score':[70,80,90]})
print(df.groupby('group')['score'].mean())
そのまま演習pandas の絞り込みとグループ化 · そのまま演習

A の点数100を1件追加し、A/B の平均を表示してください。

ヒントを見る

A の新しい点数を追加するので、group と score のリストを同じ長さにします。B のデータは変更しません。

演習の解説

A グループの平均は追加した点数に応じて変わります。

虫食いpandas の絞り込みとグループ化 · 虫食い

空欄を埋め、コードを実行してください。

chapter-14_code_35.py
print(df.groupby('group')['score'].___())
ヒントを見る

group ごとに分けた点数列の平均を計算します。グループごとに件数が違っても、それぞれの平均を求めます。

虫食いの解説
chapter-14_code_36.py
print(df.groupby('group')['score'].mean())

mean を補います。

グラフで確かめる

知識

matplotlib は線グラフ、散布図、棒グラフなどを作ります。軸の意味と単位を明記し、見た目から読み取った傾向を元データで確かめる。

chapter-14_code_37.py
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [2, 4, 3])
plt.xlabel('day')
plt.ylabel('value')
plt.show()
そのまま演習グラフで確かめる · そのまま演習

例を実行し、2日目の値を5に変更して形を比べます。

ヒントを見る

横の2に対応する縦の値だけを変更します。横と縦の同じ位置の値が一つの点を作ります。

演習の解説

折れ線の2番目の点が上がる。各点は対応する x と y の組で決まる。

虫食いグラフで確かめる · 虫食い

空欄を埋め、コードを実行してください。

chapter-14_code_38.py
import matplotlib.pyplot as plt
plt.___([1, 2], [3, 4])
plt.show()
ヒントを見る

二組の横と縦の座標を、線で結ばずに点として描きます。散布図に使う描画関数です。

虫食いの解説
chapter-14_code_39.py
import matplotlib.pyplot as plt
plt.plot([1, 2], [3, 4])
plt.show()

plot を補います。

散布図・棒グラフ・Bokeh

知識

散布図は2変数の関係、棒グラフはカテゴリ間の大きさを示しやすい。Bokeh はブラウザで操作できるグラフを作れます。目的に合わせて表示方法を選ぶ。

chapter-14_code_40.py
from bokeh.plotting import figure, show
p = figure(title='sample')
p.scatter([1,2,3], [2,1,3])
show(p)
そのまま演習散布図・棒グラフ・Bokeh · そのまま演習

同じ3点を matplotlib の scatter でも描き、点の座標一覧を表示してください。

ヒントを見る

Bokeh と matplotlib に同じ座標の組を渡します。matplotlib の点の集合から座標を取得し、一覧として表示します。

演習の解説

両方とも3点を描く。Bokeh の表示にはブラウザが使われます。

虫食い散布図・棒グラフ・Bokeh · 虫食い

空欄を埋め、コードを実行してください。

chapter-14_code_41.py
from bokeh.plotting import figure, show
p = figure()
p.___([1,2], [3,4])
show(p)
ヒントを見る

作った Bokeh の図へ、座標ごとに円形の点を加えます。figure を作る関数とは別の描画メソッドです。

虫食いの解説
chapter-14_code_42.py
from bokeh.plotting import figure, show
p = figure()
p.scatter([1,2], [3,4])
show(p)

scatter を補います。

機械学習の入口

知識

教師あり学習では入力と正解の組から規則を学び、未知データに予測を出します。訓練用と評価用のデータを分け、学習に使っていないデータで性能を見る。

chapter-14_code_43.py
from sklearn.model_selection import train_test_split
X = [[1], [2], [3], [4]]
y = [0, 0, 1, 1]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
そのまま演習機械学習の入口 · そのまま演習

訓練用と評価用の件数を1行で表示してください。

ヒントを見る

分割された説明変数の二つのリストの長さを求めます。合計が元の4件と一致することも確認します。

演習の解説

分割後の件数は len で確認できます。小標本の評価はぶれやすい。

虫食い機械学習の入口 · 虫食い

空欄を埋め、コードを実行してください。

chapter-14_code_44.py
from sklearn.model_selection import ___
X_train, X_test, y_train, y_test = train_test_split([[1],[2],[3],[4]], [0,0,1,1], random_state=0)
ヒントを見る

関数の読み込み名を次の行の呼び出し名と一致させます。二つのデータを同じ組で訓練用と評価用へ分ける関数です。

虫食いの解説
chapter-14_code_45.py
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split([[1],[2],[3],[4]], [0,0,1,1], random_state=0)

train_test_split を補います。scikit-learn の導入が必要。

分類・回帰・クラスタリング

知識

分類はカテゴリ、回帰は連続値を予測する教師あり学習。クラスタリングは正解ラベルなしで似たデータをまとめる教師なし学習。前処理と評価方法も目的に合わせて選ぶ。

chapter-14_code_46.py
from sklearn.cluster import KMeans
model = KMeans(n_clusters=2, random_state=0, n_init=10)
print(model.fit_predict([[0,0],[0,1],[9,9],[9,8]]))
そのまま演習分類・回帰・クラスタリング · そのまま演習

近い2点ずつが同じクラスタかを True/False で1行に表示してください。

ヒントを見る

クラスタ番号の大小ではなく、近い二点に同じ番号が付いたかを比較します。二組の比較結果を1行に表示します。

演習の解説

0付近と9付近の2群に分かれます。ラベル番号自体に意味はありません。

虫食い分類・回帰・クラスタリング · 虫食い

KMeans がデータを2グループへ分ける設定になるように、n_clusters の空欄を埋めてください。random_state と n_init は変更しません。

chapter-14_code_47.py
from sklearn.cluster import KMeans
model = KMeans(n_clusters=___, random_state=0, n_init=10)
ヒントを見る

データを問題で指定された個数のグループに分けます。n_clusters は番号ではなく、グループ数を受け取ります。

虫食いの解説
chapter-14_code_48.py
from sklearn.cluster import KMeans
model = KMeans(n_clusters=2, random_state=0, n_init=10)

2 を補います。

章末演習(10問)

ここには解答を載せていません。

  1. 章末演習章末演習 1

    math モジュールを使って4つの数値計算を行い,浮動小数の比較の注意点を確かめる。

    入力

    • キーボード入力なし(input() は使わない)。
    • 扱う数値:直角をはさむ2辺 3 と 4,円の半径 3,品物 23 個,1箱 5 個入り。

    処理条件

    • 標準ライブラリの math だけを使う(NumPy などの外部ライブラリは使わない)。
    • (1) 斜辺は math.sqrt で求めます。(2) 斜辺が底辺(長さ3の辺)となす角は math.atan2(4, 3) で求めたラジアンを math.degrees で度に直します。(3) 円の面積は math.pi を使います。(4) 必要な箱の数は math.ceil で切り上げる。
    • 最後に 0.1 + 0.2 == 0.3 と math.isclose(0.1 + 0.2, 0.3) の結果を表示します。

    出力

    • 1行目「斜辺: 値」は丸めずにそのまま表示します。2行目「角度: 値 度」と3行目「円の面積: 値」は f-string の .2f で小数第2位まで表示します。4行目は「箱の数: 値」。
    • 5行目「0.1 + 0.2 == 0.3: 結果」,6行目「math.isclose(0.1 + 0.2, 0.3): 結果」。コロンは半角で,その後に半角空白1個を置く。
    • 出力は全6行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    斜辺: 5.0
    角度: 53.13 度
    円の面積: 28.27
    箱の数: 5
    0.1 + 0.2 == 0.3: False
    math.isclose(0.1 + 0.2, 0.3): True
    
    ヒントを見る

    三角関数は角度をラジアンで扱うので,度で表示する前に単位を変換します。箱の数は割り算の結果を整数に「切り上げる」場面で,切り捨てとは結果が異なります。小数の等しさは「十分に近いか」で確かめる関数があります。

  2. 章末演習章末演習 2

    NumPy の配列で行う「要素ごとの計算」を,標準のリストと zip で再現します。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ:prices = [120, 250, 80, 400](単価),qty = [3, 1, 5, 2](個数)。2つのリストの長さは等しい。

    処理条件

    • NumPy は使いません。小計のリスト subtotal は,for 文と zip(prices, qty) で単価と個数を1組ずつ取り出し,append で作る(range(len(...)) による添字の操作はしない)。
    • 税込のリスト taxed は,subtotal の各要素に1.1を掛けて組み込み関数 round で整数に丸めて作ります。このデータでは端数がちょうど0.5になる値は生じません。
    • 最後の集計に限り,組み込み関数 sum と max を使ってよいでしょう。

    出力

    • 「小計: リスト」「税込: リスト」「税込合計: 値」「小計の最大: 値」の4行を表示します。リストは print でそのまま表示した形(角かっこ,半角カンマ+半角空白区切り)。コロンは半角で,その後に半角空白1個を置く。
    • 出力は全4行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    小計: [360, 250, 400, 800]
    税込: [396, 275, 440, 880]
    税込合計: 1991
    小計の最大: 800
    
    ヒントを見る

    2つのリストの同じ位置の値を組にして取り出す関数を for 文で回すと,添字を使わずに要素ごとの計算ができます。小数を掛けた結果には誤差が含まれるので,整数にそろえてから表示しましょう。

  3. 章末演習章末演習 3

    3店舗×4週の売上を2次元リストで表し,NumPy の axis に当たる行方向・列方向の集計を二重ループで確かめる。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ:sales = [[3, 5, 2, 4], [6, 1, 7, 2], [4, 4, 4, 4]](1行が1店舗,1列が1週)。

    処理条件

    • NumPy は使いません。形は (行数, 列数) のタプルで,len(sales) と len(sales[0]) から求めます。
    • 行ごとの合計(店舗ごと)は,各行に組み込み関数 sum を使ってよいでしょう。
    • 列ごとの合計(週ごと)は,外側の for 文で列番号を固定し,内側の for 文で行番号を動かす二重ループで求めます。zip(*sales) による転置は使いません。
    • 最後に,行ごとの合計の総和と列ごとの合計の総和をそれぞれ求める(ここでは sum を使ってよい)。

    出力

    • 「形: タプル」「行ごとの合計: リスト」「列ごとの合計: リスト」「行合計の総計: 値」「列合計の総計: 値」の5行を表示します。タプルとリストは print でそのまま表示した形。コロンは半角で,その後に半角空白1個を置く。
    • 出力は全5行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    形: (3, 4)
    行ごとの合計: [14, 16, 16]
    列ごとの合計: [13, 10, 13, 10]
    行合計の総計: 46
    列合計の総計: 46
    
    ヒントを見る

    2次元リストの要素は「行番号,列番号」の順に添字を付けて取り出します。列ごとの合計では,どちらの番号を外側のループで固定するかを先に決め,内側のループに入る前に合計用の変数を0に戻そう。

  4. 章末演習章末演習 4

    pandas の groupby に当たる集計を辞書で行い,店舗ごとの合計と平均を表にします。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ(辞書のリスト): records = [{"店舗": "東", "売上": 1200}, {"店舗": "西", "売上": 800}, {"店舗": "東", "売上": 600}, {"店舗": "西", "売上": 900}, {"店舗": "東", "売上": 1500}]

    処理条件

    • pandas,collections,itertools は使いません。
    • 店舗名をキーとする辞書 totals(売上の合計)と counts(件数)を用意し,records を for 文で1周しながら辞書の get メソッドで両方を更新します。
    • 平均は「合計 ÷ 件数」で求めます。
    • 店舗は sorted(totals) の順(文字コード順)に表示します。

    出力

    • 1行目に見出し「店舗 | 合計 | 平均」を表示する(この問題では見出しを出力に含める)。
    • 2行目以降は店舗ごとに「店舗 | 合計 | 平均」とし,縦棒は半角でその前後に半角空白1個を置く。合計は整数,平均は .1f で小数第1位まで表示します。
    • 出力は全3行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    店舗 | 合計 | 平均
    東 | 3300 | 1100.0
    西 | 1700 | 850.0
    
    ヒントを見る

    1件の記録を読むたびに,その店舗の合計と件数の両方を更新します。まだ現れていない店舗も既定値を使えば同じ式で扱える。平均は全件を読み終えてから計算しましょう。

  5. 章末演習章末演習 5

    欠損値 None を含む気温データを,statistics モジュールで集計し,欠損を平均で補います。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ:temps = [22.5, None, 24.0, None, 21.5, 23.0, 25.0]。有効な値は1個以上あります。

    処理条件

    • NumPy・pandas は使いません。
    • for 文で None 以外の値だけを集めたリスト valid を作ります。None の判定には is None または is not None を使います。
    • 欠損の個数は len(temps) - len(valid) で求めます。平均と中央値は statistics.mean と statistics.median を valid に使って求めます。
    • 補完後のリスト filled は新しく作り,None の位置に「平均を round(平均, 1) で小数第1位に丸めた値」を入れます。temps 自体は書き換えません。
    • 24度以上(24.0 ちょうどを含む)の日数は,valid を for 文で数える。

    出力

    • 「欠損: 値」「平均: 値」「中央値: 値」「補完後: リスト」「24度以上: 値 日」の5行を表示します。平均と中央値は .1f で小数第1位まで,リストは print でそのまま表示した形とします。コロンは半角で,その後に半角空白1個を置く。
    • 出力は全5行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    欠損: 2
    平均: 23.2
    中央値: 23.0
    補完後: [22.5, 23.2, 24.0, 23.2, 21.5, 23.0, 25.0]
    24度以上: 2 日
    
    ヒントを見る

    欠損を含んだまま平均を求めることはできないので,まず有効な値だけを取り出し,それを集計と補完の両方に使います。補完では元のリストを順に見て,欠損かどうかで追加する値を切り替えよう。境界の24度が含まれるかは比較演算子で決まる。

  6. 章末演習章末演習 6

    グラフ描画ライブラリを使わずに,投票数を文字の横棒グラフとして表示します。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ:votes = {"りんご": 7, "みかん": 4, "ぶどう": 9, "もも": 4}。票数はすべて正の整数。

    処理条件

    • matplotlib と collections は使いません。総票数は sum(votes.values()) で求めてよいでしょう。
    • for 文で votes.items() から (票数, 名前) のタプルのリストを作り,sort(reverse=True) で並べ替える。key= 引数は使いません。
    • その結果,票数の多い順になり,票数が同じ場合は名前の文字コードの大きいほうが先になります。
    • 棒は1票を半角の # 1個で表し,文字列の繰り返し * で作ります。割合は「票数 ÷ 総票数 × 100」。

    出力

    • 1項目につき1行,「名前 | 棒 票数 (割合%)」と表示します。縦棒・かっこ・% は半角で,各部分の間は半角空白1個(( の直後と % の直前には空白を置かない)。割合は .1f で小数第1位まで表示します。
    • 出力は全4行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    ぶどう | ######### 9 (37.5%)
    りんご | ####### 7 (29.2%)
    もも | #### 4 (16.7%)
    みかん | #### 4 (16.7%)
    
    ヒントを見る

    辞書は値の大きい順に直接並べられないので,並べ替えの基準にしたい値を先頭に置いた組のリストに作り替える。棒の長さは,文字列に整数を掛けると同じ文字が繰り返されることを利用しましょう。

  7. 章末演習章末演習 7

    関数 y = x² − 4x + 3 の座標の表を出力し,グラフの形(x 軸との交点・最小点・対称性)を確かめる。

    入力

    • キーボード入力なし(input() は使わない)。
    • x は −1 から 5 までの整数(−1, 0, 1, …, 5 の7個)。

    処理条件

    • matplotlib・NumPy は使いません。
    • for 文と range(-1, 6) で (x, y) のタプルを並べたリスト table を作ります。y は x ** 2 - 4 * x + 3。
    • y が0になる x は,table を for 文で調べてリストに集める。
    • 最小点は min や sorted を使わず,table の先頭を仮の最小とし,y がそれより小さい(<)点が現れたら入れ替えて求めます。
    • 左右対称かどうかは,y の値を順に並べたリストとそれを逆順にしたリスト(スライス [::-1] を使ってよい)が等しいかで判定します。

    出力

    • 1行目に見出し「 x | y」を表示する(この問題では見出しを出力に含める。先頭に半角空白1個,| の後に半角空白2個)。
    • 2〜8行目は x の小さい順に「x | y」を表示します。x と y はそれぞれ f-string の書式 2d(幅2の右寄せ)で表示し,間に「 | 」(半角空白・縦棒・半角空白)を置く。
    • 続けて「y=0 の x: リスト」「最小点: タプル」「左右対称: 真偽値」を表示します。コロンは半角で,その後に半角空白1個を置く。
    • 出力は全11行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

     x |  y
    -1 |  8
     0 |  3
     1 |  0
     2 | -1
     3 |  0
     4 |  3
     5 |  8
    y=0 の x: [1, 3]
    最小点: (2, -1)
    左右対称: True
    
    ヒントを見る

    まず表のリストを作り,表示・交点探し・最小点探し・対称性の確認はすべてそのリストを読み直して行います。最小点は「これまでで最小の点」を1つ覚えておき,比較のたびに更新する考え方で求めよう。

  8. 章末演習章末演習 8

    勉強時間と得点のデータを訓練用と評価用に分け,最小二乗法の回帰直線を自作して予測誤差を評価します。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ:xs = [1, 2, 3, 4, 5, 6, 7, 8](勉強時間),ys = [52, 58, 65, 71, 79, 83, 90, 97](得点)。

    処理条件

    • NumPy・scikit-learn と statistics.linear_regression は使いません。平均には statistics.mean を使ってよいでしょう。
    • スライスで先頭6件を訓練用,残り2件を評価用に分ける(並び順のまま分け,乱数は使わない)。
    • 訓練用だけを使い,傾き a =(x の偏差 × y の偏差)の和 ÷(x の偏差の2乗)の和,切片 b = y の平均 − a × x の平均,を求めます。偏差の和は for 文と zip で足し上げる。
    • 評価用の各 x について予測値 a x + b を求め,平均絶対誤差 MAE =(|正解 − 予測| の平均)を求めます。

    出力

    • 「a = 値」「b = 値」「x=7 の予測: 値」「x=8 の予測: 値」「MAE: 値」の5行を表示します。数値はすべて f-string の .1f で小数第1位まで表示します。= の前後と,コロンの後には半角空白1個を置く(「x=7」の = の前後には空白を置かない)。
    • 出力は全5行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    a = 6.4
    b = 45.6
    x=7 の予測: 90.4
    x=8 の予測: 96.8
    MAE: 0.3
    
    ヒントを見る

    最初に訓練用と評価用を分け,傾きと切片の計算に評価用の値が混ざっていないかを確かめる。傾きの分子と分母は,同じループの中で2つの変数に別々に足し上げられます。誤差は向きを無視した大きさで平均しましょう。

  9. 章末演習章末演習 9

    果物の(重さ g,糖度)から種類を当てる最近傍法(1-NN)の分類器を自作し,正解率を求めます。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ:
    • train = [((90, 11), "みかん"), ((100, 12), "みかん"), ((85, 10), "みかん"), ((280, 14), "りんご"), ((300, 13), "りんご"), ((260, 15), "りんご")]
    • test = [((95, 12), "みかん"), ((270, 13), "りんご"), ((170, 12), "りんご"), ((120, 11), "みかん")]

    処理条件

    • scikit-learn は使いません。距離は math.dist で求めます。
    • 関数 predict(x) を定義し,train を for 文で1周して,最も距離が小さい点のラベルを返します。min や sorted は使わず,これまでの最小距離とそのラベルを変数で覚えて更新します。距離が等しい点がある場合は先に現れた点を採用する(< で比較する)。
    • test の各データを順に予測し,予測と正解が一致した件数から正解率 = 一致件数 ÷ len(test) を求めます。

    出力

    • 評価用データ1件につき1行,「座標のタプル 予測: ラベル 正解: ラベル」と表示します。タプルは print でそのまま表示した形で,各部分の間は半角空白1個(コロンは半角)。
    • 最後の行は「正解率: 値」とし,値は割り算の結果をそのまま表示します。
    • 出力は全5行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    (95, 12) 予測: みかん 正解: みかん
    (270, 13) 予測: りんご 正解: りんご
    (170, 12) 予測: みかん 正解: りんご
    (120, 11) 予測: みかん 正解: みかん
    正解率: 0.75
    
    ヒントを見る

    予測の関数では,最小距離とそのラベルの2つを覚えておく。最初の1点をどう扱うか(まだ比べる相手がない状態)を決めてからループを書こう。重さと糖度は単位の大きさが違うため,距離は主にどちらの差で決まるかも考えてみるとよいでしょう。

  10. 章末演習章末演習 10

    2次元の点を k=2 のクラスタに分ける k-means 法を自作し,割り当てが変わらなくなるまで繰り返します。

    入力

    • キーボード入力なし(input() は使わない)。
    • 固定データ:points = [(1, 1), (1.5, 2), (2, 1.5), (8, 8), (8.5, 9), (9, 8)]。

    処理条件

    • scikit-learn・NumPy は使いません。距離は math.dist で求めます。
    • 初期中心は centers = [points[0], points[1]],前回の割り当て labels は None で始める。
    • while True: で次を繰り返します。(1) 各点を近いほうの中心の番号(0 または 1)に割り当てたリストを作ります。距離が等しければ0番とします。(2) その回の番号と割り当てを表示します。(3) 割り当てが前回と等しければ break で終了します。(4) 等しくなければ前回の割り当てを更新し,各クラスタの x 座標の平均と y 座標の平均を新しい中心にする(平均には sum と len を使ってよい)。
    • このデータでは点が1つもないクラスタは生じません。

    出力

    • 各回の割り当てを「n回目: リスト」と表示する(n は1から数える整数で,「回目」の前に空白を置きません。リストは print でそのまま表示した形)。
    • 終了後に「中心0: (x, y)」「中心1: (x, y)」を表示します。x と y は .2f で小数第2位まで表示し,半角かっこ・半角カンマ+半角空白で囲む。コロンは半角で,その後に半角空白1個を置く。
    • 出力は全5行。実行例と同じ順序・同じ文字(半角・全角,大文字・小文字を含む)で表示します。実行例にない見出し・空行・余分な空白・デバッグ用の表示は出さない(assert は何も表示しないので自己確認に使ってよい)。

    実行例

    1回目: [0, 1, 1, 1, 1, 1]
    2回目: [0, 0, 0, 1, 1, 1]
    3回目: [0, 0, 0, 1, 1, 1]
    中心0: (1.50, 1.50)
    中心1: (8.50, 8.33)
    
    ヒントを見る

    1回の繰り返しを「割り当てを作る→表示する→前回と比べる→中心を更新する」の4段階に分けて書こう。比べる前に前回の割り当てを上書きすると,いつまでも終了しないか,すぐに終了してしまう。距離が等しい場合の扱いは比較演算子で決まる。