データ処理における3つの主要な正規化・標準化手法の計算式と特徴の解説

こんにちは。ゆうせいです。

収集したデータには、数値の大きさや単位がバラバラに含まれていることが多々あります。例えば、身長(cm)と体重(kg)では数値の範囲が異なるため、そのまま比較すると正確な分析が困難です。こうしたデータの「尺度(ものさし)」を揃える処理を正規化や標準化と呼びます。

提示されたプログラムに含まれる3つの計算手法について、それぞれの定義と仕組みを解説します。

各手法の解説には、手計算で確かめられる計算例と練習問題を添えました。紙と電卓を用意し、数値を計算式に当てはめながら読み進めてください。

1. 最小最大正規化(Min-Max Normalization)

最小最大正規化は、データの全範囲を0から1の間に収める手法です。

仕組みと比喩

データの最小値を0、最大値を1として、その間の値を相対的な位置で表現します。これは、100点満点のテストと50点満点のテストの結果を、どちらも「達成率(パーセント)」に換算して比較することに似ています。

計算式

各データ x に対して、新しい値 x' は以下の式で求められます。

x' = \frac{x - \min(x)}{\max(x) - \min(x)}

ここで、min(x) はデータ全体の最小値、max(x) は最大値を示します。

計算例:5人のテストの点数を0から1に変換する

5人のテストの点数が、40点、50点、60点、70点、90点だったとします。5つの点数を、3つの手順で最小最大正規化してみましょう。

手順1:最小値と最大値を探します。最小値は40、最大値は90です。

手順2:計算式の分母にあたる「最大値 - 最小値」を求めます。90 - 40 = 50 となります。

手順3:それぞれの点数から最小値の40を引き、手順2で求めた50で割ります。50点の場合は次のように計算します。

x' = \frac{50 - 40}{90 - 40} = \frac{10}{50} = 0.2

残りの点数も同じ手順で計算した結果が、次の表です。

元の点数計算変換後の値
40(40 - 40) ÷ 500
50(50 - 40) ÷ 500.2
60(60 - 40) ÷ 500.4
70(70 - 40) ÷ 500.6
90(90 - 40) ÷ 501

最小値の40点が0に、最大値の90点が1に変換されました。60点の0.4という値は、最小値から最大値までの幅のうち、下から40%の位置にあることを表しています。

間違えやすい点:点数を最大値で割るだけの計算(60 ÷ 90 = 約0.67)と混同しないように注意してください。仕組みと比喩で挙げた達成率は、最小値を0点、最大値を満点と見なした場合の計算に当たります。最小値が0ではないデータでは、分子と分母の両方から最小値を引いてから割ります。

計算結果は、記事の末尾にあるプログラムでも確かめられます。プログラムは、掲載しているコードをテキストエディタに貼り付け、拡張子が .html のファイルとして保存し、インターネットに接続したパソコンのブラウザで開くと動きます。データ欄に 40, 50, 60, 70, 90 と半角のカンマで区切って入力し、手法に「最小最大正規化 (0-1)」を選んで実行すると、0.0000、0.2000、0.4000、0.6000、1.0000 と表示されます。手計算の結果と一致することを確かめてください。

メリットとデメリット

  • メリット:すべてのデータが0から1の範囲に収まるため、計算の扱いが容易になります。
  • デメリット:外れ値(極端に大きい、または小さい値)が1つでもあると、他の大部分のデータが狭い範囲に固まってしまい、情報の差異が失われます。

練習問題1:最小最大正規化

解答を読む前に、紙の上で計算してみてください。

問1:ある店舗の5日間の来客数は、10人、20人、25人、40人、60人でした。5つの数値を最小最大正規化してください。

問2:計算例の5人の点数のうち、90点を誤って540点と入力してしまいました。40、50、60、70、540 の5つの数値を最小最大正規化してください。また、40点から70点までの4人の値が、計算例の結果からどのように変わったかを説明してください。

練習問題1の解答と解説

問1の解答:0、0.2、0.3、0.6、1

最小値は10、最大値は60なので、分母は 60 - 10 = 50 です。

元の値計算変換後の値
10(10 - 10) ÷ 500
20(20 - 10) ÷ 500.2
25(25 - 10) ÷ 500.3
40(40 - 10) ÷ 500.6
60(60 - 10) ÷ 501

問2の解答:0、0.02、0.04、0.06、1

最大値が540に変わるため、分母は 540 - 40 = 500 になります。

元の値計算変換後の値計算例での値
40(40 - 40) ÷ 50000
50(50 - 40) ÷ 5000.020.2
60(60 - 40) ÷ 5000.040.4
70(70 - 40) ÷ 5000.060.6
540(540 - 40) ÷ 50011(90点)

計算例では0から0.6まで広がっていた4人の値が、0から0.06までの狭い範囲に集まりました。50点、60点、70点の値はいずれも10分の1になり、4人の点数の違いを読み取りにくくなっています。1つの値が外れ値に変わっただけで、分母が50から500に大きくなったことが原因です。デメリットとして挙げた「他の大部分のデータが狭い範囲に固まってしまう」現象を、数値で確認できました。


2. 標準化(Z-score Normalization)

標準化は、データの平均値を0、標準偏差を1にする手法です。

仕組みと比喩

データの平均からのズレを基準にする方法です。これは、学校のテストで使われる「偏差値」をイメージすると分かりやすいでしょう。平均点にいる人を0とし、そこからどれくらい離れているかを数値化します。

計算式

平均を μ、標準偏差を σ とすると、新しい値 z は以下の式で計算されます。

z = \frac{x - \mu}{\sigma}

計算例:5人のテストの点数を標準化する

5人のテストの点数が、45点、55点、60点、65点、75点だったとします。標準化では、計算式に登場する平均 μ(ミュー)と標準偏差 σ(シグマ)を先に求めます。標準偏差とは、データが平均からどれくらい散らばっているかを表す数値です。

手順1:平均を求めます。5人の点数を合計し、データの個数である5で割ります。

(45 + 55 + 60 + 65 + 75) ÷ 5 = 300 ÷ 5 = 60

手順2:それぞれの点数から平均の60を引きます。この差を偏差と呼びます。45点の偏差は 45 - 60 = -15、75点の偏差は 75 - 60 = 15 です。5人の偏差は、順に -15、-5、0、5、15 となります。

手順3:偏差を二乗して、5人分を合計します。偏差をそのまま合計すると、プラスとマイナスが打ち消し合って必ず0になるため、二乗してから合計します。5人の偏差の二乗は、順に 225、25、0、25、225 です。

225 + 25 + 0 + 25 + 225 = 500

手順4:手順3で求めた合計をデータの個数で割り、その平方根を求めます。求めた値が標準偏差です。

\sigma = \sqrt{\frac{225 + 25 + 0 + 25 + 225}{5}} = \sqrt{\frac{500}{5}} = \sqrt{100} = 10

手順5:それぞれの偏差を、標準偏差の10で割ります。75点の場合は次のように計算します。

z = \frac{75 - 60}{10} = \frac{15}{10} = 1.5

手順2から手順5までの結果をまとめると、次の表になります。

元の点数偏差(点数 - 平均)偏差の二乗変換後の値 z
45-15225-1.5
55-525-0.5
60000
655250.5
75152251.5
合計05000

変換後の値 z は、Zスコアとも呼ばれます。5人分を合計すると0になり、平均が0に揃ったことを確認できます。75点の1.5という値は、平均よりも標準偏差1.5個分だけ高い位置にあることを意味します。

変換後の5つの値に対して同じ手順をもう一度行うと、平均は0、二乗の合計は 2.25 + 0.25 + 0 + 0.25 + 2.25 = 5 です。データの個数で割ると 5 ÷ 5 = 1、1の平方根は1なので、標準偏差は1になります。標準化の定義どおり、平均が0、標準偏差が1に揃いました。

学校で使われる偏差値は、変換後の値 z を10倍して50を足した数値です。75点の偏差値は 1.5 × 10 + 50 = 65、45点の偏差値は -1.5 × 10 + 50 = 35 となります。仕組みと比喩で触れた偏差値は、標準化の結果を読みやすい数値に直したものです。

手順2から手順4までを記号でまとめると、次の式になります。

\sigma = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (x_{i} - \mu)^2}

n はデータの個数を表します。x の右下に付いた i は、i 番目のデータであることを示します。Σ(大文字のシグマ)は、i を1から n まで変えながら合計することを表す記号です。標準偏差を表す σ(小文字のシグマ)とは別の記号なので、混同しないようにしてください。

間違えやすい点:手順4で平方根を求め忘れると、標準偏差の10ではなく、平方根を求める前の100で割ってしまいます。平方根を求める前の値は分散と呼ばれ、標準偏差とは別の数値です。

手計算とプログラムの結果が一致しない理由

記事の末尾にあるプログラムで、データ欄に 45, 55, 60, 65, 75 と入力し、手法に「標準化 (Z-score)」を選んで実行すると、-1.3416、-0.4472、0.0000、0.4472、1.3416 と表示されます。手計算で求めた -1.5、-0.5、0、0.5、1.5 とは一致しません。

一致しない原因は、標準偏差の求め方が2種類あることです。

  • データの個数 n で割る方法:手元にあるデータそのものの散らばりを表します。計算例ではこちらを使いました。
  • n - 1 で割る方法:手元のデータを、より大きな集団から取り出した一部(標本)と見なし、集団全体の散らばりを推定するときに使います。

プログラムで使用している math.std 関数は、特に指定しない場合、n - 1 で割る方法で計算します。今回のデータでは、標準偏差は次の値になります。

\sqrt{\frac{500}{5 - 1}} = \sqrt{125} \approx 11.18

≈ は、ほぼ等しいことを表す記号です。45点の場合は -15 ÷ 11.18 = 約-1.34 となり、プログラムが表示した -1.3416 と小数第2位まで一致します。

どちらの方法も誤りではなく、データの個数が多いほど2つの方法の差は小さくなります。注意が必要なのは、ツールによって初期設定が異なる点です。Excelには、n で割る STDEV.P 関数と、n - 1 で割る STDEV.S 関数の両方があります。Pythonのライブラリでは、NumPyの std 関数は初期設定で n で割り、pandasの std メソッドは初期設定で n - 1 で割ります。ツールを使って標準化するときは、どちらの方法で計算されているかを確認してください。

プログラムの結果を手計算と一致させたい場合は、プログラムの中から、標準偏差を求めている次の1行を探します。

javascript

const std = math.std(rawData);

見つけた1行を、次のように書き換えます。追加した uncorrected は、n で割る方法を指定する値です。

javascript

const std = math.std(rawData, 'uncorrected');

書き換えたファイルを保存し、ブラウザで開き直してから同じデータで実行すると、-1.5000、-0.5000、0.0000、0.5000、1.5000 と表示されます。

メリットとデメリット

  • メリット:外れ値の影響を最小最大正規化よりも受けにくく、多くの統計手法や機械学習アルゴリズムに適しています。
  • デメリット:変換後のデータの範囲が一定(0から1など)にならないため、最大値や最小値が事前に予測できない場合があります。

練習問題2:標準化

標準偏差は、計算例と同じく n で割る方法で求めてください。

問1:ある窓口の5日間の問い合わせ件数は、3件、5件、7件、11件、14件でした。5つの数値を標準化してください。

問2:Aさんのテスト結果は、英語が70点、数学が60点でした。英語は平均60点・標準偏差10点、数学は平均50点・標準偏差5点です。受験者全体の中での位置が高いのは、どちらの科目でしょうか。それぞれの z を計算して答えてください。

練習問題2の解答と解説

問1の解答:-1.25、-0.75、-0.25、0.75、1.5

平均は (3 + 5 + 7 + 11 + 14) ÷ 5 = 40 ÷ 5 = 8 です。偏差と偏差の二乗は、次の表のとおりです。

元の値偏差(値 - 平均)偏差の二乗変換後の値 z
3-525-1.25
5-39-0.75
7-11-0.25
11390.75
146361.5
合計0800

\sigma = \sqrt{\frac{25 + 9 + 1 + 9 + 36}{5}} = \sqrt{\frac{80}{5}} = \sqrt{16} = 4

それぞれの偏差を標準偏差の4で割ると、表の右端の値になります。

問2の解答:数学

英語の z は、次のとおりです。

z = \frac{70 - 60}{10} = \frac{10}{10} = 1

数学の z は、次のとおりです。

z = \frac{60 - 50}{5} = \frac{10}{5} = 2

点数そのものは英語の70点の方が高いものの、z は数学の方が大きくなりました。数学は標準偏差が小さく、受験者の点数が平均の近くに集まっています。そのため、平均より10点高いだけでも、全体の中での位置は英語より高くなります。偏差値に直すと、英語は 1 × 10 + 50 = 60、数学は 2 × 10 + 50 = 70 です。標準化を行うと、平均や散らばりが異なるデータ同士を、同じ基準で比べられます。


3. L2正規化(L2 Normalization / Unit Vector)

L2正規化は、データ群を1つのベクトル(矢印)と見なし、その長さ(ノルム)を1にする手法です。

仕組みと比喩

データの数値そのものよりも、「データの成分比率」や「方向」を重視します。例えば、料理のレシピで「塩1g、砂糖2g」という情報を、「塩1:砂糖2」という比率に変換するようなものです。全体の分量がどれだけ増えても、この比率(方向)は変わりません。

計算式

各要素の二乗和の平方根(L2ノルム)で各データを割ります。

x' = \frac{x}{\sqrt{\sum_{i=1}^{n} x_{i}^2}}

プログラム内では math.norm 関数を用いてこの分母の値を算出しています。

計算例:塩と砂糖の分量をL2正規化する

仕組みと比喩で取り上げたレシピの例を、計算しやすい数値に変えて考えます。塩3g、砂糖4gのレシピを、(3, 4) という2つの数値の組(ベクトル)として扱います。

手順1:それぞれの数値を二乗して合計します。3 × 3 + 4 × 4 = 9 + 16 = 25 です。

手順2:手順1で求めた合計の平方根を求めます。求めた値が、ベクトルの長さ(L2ノルム)です。

\sqrt{3^2 + 4^2} = \sqrt{9 + 16} = \sqrt{25} = 5

横に3、縦に4だけ進む矢印を方眼紙に描くと、矢印の長さは5になります。直角三角形の辺の長さを求める三平方の定理と同じ計算です。

手順3:それぞれの数値を、L2ノルムの5で割ります。

項目元の値計算変換後の値
塩33 ÷ 50.6
砂糖44 ÷ 50.8

変換後の値で長さを計算し直すと、0.6 × 0.6 + 0.8 × 0.8 = 0.36 + 0.64 = 1 となり、1の平方根は1です。ベクトルの長さが1に揃ったことを確認できました。長さが1のベクトルは、単位ベクトル(Unit Vector)と呼ばれます。

続いて、分量を2倍にした「塩6g、砂糖8g」のレシピを計算します。

\sqrt{6^2 + 8^2} = \sqrt{36 + 64} = \sqrt{100} = 10

6 ÷ 10 = 0.6、8 ÷ 10 = 0.8 となり、変換後の値は元のレシピと同じ (0.6, 0.8) です。全体の分量が2倍になっても、塩と砂糖の比率が同じであれば、L2正規化の結果は変わりません。

間違えやすい点:数値の合計で割る計算(3 ÷ 7 = 約0.43)と混同しないように注意してください。L2正規化では、二乗の合計の平方根で割ります。変換後の値をそのまま合計しても 0.6 + 0.8 = 1.4 となり、1にはなりません。1になるのは、変換後の値を二乗した合計です。

記事の末尾にあるプログラムで、データ欄に 3, 4 と入力し、手法に「L2正規化 (Unit Vector)」を選んで実行すると、0.6000 と 0.8000 が表示されます。

メリットとデメリット

  • メリット:データの大きさ(スケール)に左右されず、複数の項目間の「パターンの類似性」を比較するのに非常に有効です。
  • デメリット:個々の数値が持っていた絶対的な大きさの情報は完全に失われます。

練習問題3:L2正規化

問1:4つの数値 1、2、2、4 をL2正規化してください。変換後の値をそれぞれ二乗して合計し、1になることも確かめてください。

問2:3つの店舗について、商品Xと商品Yの月間売上(単位は万円)を調べました。店舗Aは (30, 40)、店舗Bは (6, 8)、店舗Cは (40, 30) です。3店舗のデータをそれぞれL2正規化し、売上の構成パターンが同じ店舗の組み合わせを答えてください。

練習問題3の解答と解説

問1の解答:0.2、0.4、0.4、0.8

\sqrt{1^2 + 2^2 + 2^2 + 4^2} = \sqrt{1 + 4 + 4 + 16} = \sqrt{25} = 5

L2ノルムは5なので、1 ÷ 5 = 0.2、2 ÷ 5 = 0.4、4 ÷ 5 = 0.8 となります。変換後の値を二乗して合計すると、0.04 + 0.16 + 0.16 + 0.64 = 1 です。

問2の解答:店舗Aと店舗B

店舗Aと店舗CのL2ノルムは、どちらも次の値になります。

\sqrt{30^2 + 40^2} = \sqrt{900 + 1600} = \sqrt{2500} = 50

店舗BのL2ノルムは、計算例の2倍のレシピと同じ計算で10です。それぞれの数値をL2ノルムで割ると、次の表になります。

店舗元の値L2ノルム変換後の値
A(30, 40)50(0.6, 0.8)
B(6, 8)10(0.6, 0.8)
C(40, 30)50(0.8, 0.6)

店舗Aと店舗Bは売上の規模が5倍違いますが、変換後の値はどちらも (0.6, 0.8) になりました。商品Yが商品Xより多く売れるという構成が共通しています。店舗Cは、売上の合計が店舗Aと同じ70万円でも、変換後の値は (0.8, 0.6) となり、商品Xが中心の店舗だと分かります。

変換後の値だけを見ても、店舗Aと店舗Bのどちらの売上規模が大きいかは判断できません。デメリットとして挙げた「絶対的な大きさの情報が失われる」点も、この例で確認できます。


4. 総合演習:同じデータを3つの手法で変換する

3つの手法は、同じデータに当てはめても、それぞれ異なる結果を返します。仕上げとして、1組のデータを3通りに変換し、結果を見比べてください。

総合演習の問題

5つの商品の1日の販売個数は、1個、3個、4個、5個、7個でした。

問1:5つの数値を最小最大正規化してください。割り切れない値は、小数第5位を四捨五入して小数第4位まで求めてください。

問2:5つの数値を標準化してください。標準偏差は、n で割る方法で求めてください。

問3:5つの数値をL2正規化してください。

問4:問1から問3の結果を見比べて、次の3つの特徴に当てはまる手法をそれぞれ答えてください。

  • 特徴ア:変換後の値に、0と1が必ず含まれます。
  • 特徴イ:元の値がすべてプラスでも、変換後の値にマイナスの値が含まれます。
  • 特徴ウ:元の値同士の倍率(7は1の7倍)が、変換後もそのまま保たれます。

総合演習の解答と解説

元の値最小最大正規化標準化L2正規化
10-1.50.1
30.3333-0.50.3
40.500.4
50.66670.50.5
711.50.7

問1の解説:最小値は1、最大値は7なので、分母は 7 - 1 = 6 です。3の場合は (3 - 1) ÷ 6 = 2 ÷ 6 = 約0.3333 となります。

問2の解説:平均は (1 + 3 + 4 + 5 + 7) ÷ 5 = 20 ÷ 5 = 4 です。偏差は -3、-1、0、1、3 で、二乗すると 9、1、0、1、9 になります。

\sigma = \sqrt{\frac{9 + 1 + 0 + 1 + 9}{5}} = \sqrt{\frac{20}{5}} = \sqrt{4} = 2

それぞれの偏差を標準偏差の2で割ると、-1.5、-0.5、0、0.5、1.5 です。

標準化の計算例(45、55、60、65、75)と同じ結果になりました。1、3、4、5、7 は、計算例の点数から40を引いて5で割った数値に当たります。標準化では平均を引いて標準偏差で割るため、数値全体を一定の数だけずらしたり、一定の倍率で縮めたりした違いは、結果に残りません。単位や目盛りが異なるデータを同じ基準に揃えられるのは、この性質によるものです。

問3の解説:L2ノルムは次のとおり10なので、それぞれの数値を10で割ります。

\sqrt{1^2 + 3^2 + 4^2 + 5^2 + 7^2} = \sqrt{1 + 9 + 16 + 25 + 49} = \sqrt{100} = 10

問4の解答:特徴アは最小最大正規化、特徴イは標準化、特徴ウはL2正規化

  • 最小最大正規化は、最小値を0、最大値を1に固定します。そのため、変換後の値には0と1が必ず含まれます。ただし、すべての値が同じデータは、分母が0になるため計算できません。
  • 標準化は、平均を0に移します。平均より小さいデータは、変換後にマイナスの値になります。
  • L2正規化は、すべての値を同じ数(L2ノルム)で割るだけです。そのため、0.7 ÷ 0.1 = 7 のように、元の値同士の倍率が保たれます。

3つの結果は、いずれも元のデータの大小の順番を保っています。異なるのは、何を基準にして数値を揃えるかという点です。

実務では、計算に使う数値の取り方が手法によって異なります。最小最大正規化と標準化は、身長や点数のような1つの項目について、複数人分の値をまとめて変換します。L2正規化は、塩と砂糖の分量のように、1件のデータが持つ複数の項目を1つのベクトルとして変換するのが一般的です。総合演習では、結果を見比べるために、同じ数値に3つの手法を当てはめました。

最小最大正規化とL2正規化の結果は、記事の末尾にあるプログラムでそのまま確認できます。標準化の結果は、「手計算とプログラムの結果が一致しない理由」で紹介した書き換えを行うと、手計算と同じ値が表示されます。


まとめ

これら3つの手法は、分析の目的に応じて使い分けることが重要です。

  • データの範囲を厳密に揃えたい場合は「最小最大正規化」
  • データの分布や偏差を重視する場合は「標準化」
  • データの比率や方向性を比較したい場合は「L2正規化」

次の学習ステップとして、まずは手元の数値をこれらの式に当てはめて計算し、結果がどのように変化するかを確認してください。その後、実際のプログラミング言語を用いて、外れ値を含んだデータセットで各手法の挙動の違いをシミュレーションしてみることを推奨します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Advanced Data Normalizer</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.8.0/math.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 2rem; background: #f0f2f5; }
        .container { max-width: 900px; margin: auto; background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
        .controls { display: grid; grid-template-columns: 1fr 1fr auto; gap: 1rem; margin-bottom: 2rem; align-items: end; }
        .control-group { display: flex; flex-direction: column; gap: 5px; }
        input, select, button { padding: 10px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; }
        button { background: #007bff; color: white; border: none; font-weight: bold; transition: 0.2s; }
        button:hover { background: #0056b3; }
        .info-box { background: #e7f3ff; padding: 10px; border-radius: 6px; margin-bottom: 1rem; font-size: 0.85rem; color: #0c5460; }
        table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
        th, td { border-bottom: 1px solid #eee; padding: 12px; text-align: right; }
        th { background: #fafafa; color: #666; }
        canvas { margin-top: 2rem; background: #fff; }
    </style>
</head>
<body>

<div class="container">
    <h2>📊 データ正規化 & L2スケーリング</h2>
    
    <div class="info-box">
        <strong>L2正規化 (Unit Vector):</strong> 各データをベクトルの成分と考え、全体のノルム(長さ)が1になるよう変換します。これはコサイン類似度を算出する前段階の処理と同じです。
    </div>

    <div class="controls">
        <div class="control-group">
            <label>データ (カンマ区切り):</label>
            <input type="text" id="dataInput" value="3, 4, 5, 2, 8">
        </div>
        <div class="control-group">
            <label>手法:</label>
            <select id="method">
                <option value="minmax">最小最大正規化 (0-1)</option>
                <option value="zscore">標準化 (Z-score)</option>
                <option value="l2">L2正規化 (Unit Vector)</option>
            </select>
        </div>
        <button onclick="processData()">実行</button>
    </div>

    <div id="resultArea" style="display:none;">
        <canvas id="myChart"></canvas>
        <table>
            <thead><tr><th>元の値</th><th>処理後の値</th></tr></thead>
            <tbody id="resultBody"></tbody>
        </table>
    </div>
</div>

<script>
let chartInstance = null;

function processData() {
    const input = document.getElementById('dataInput').value;
    const method = document.getElementById('method').value;
    const rawData = input.split(',').map(x => parseFloat(x.trim())).filter(x => !isNaN(x));
    
    if (rawData.length < 2) { alert("2つ以上の数値を入力してください"); return; }

    let processedData = [];
    let formula = "";

    if (method === 'minmax') {
        const min = math.min(rawData);
        const max = math.max(rawData);
        processedData = rawData.map(x => (x - min) / (max - min));
    } 
    else if (method === 'zscore') {
        const mean = math.mean(rawData);
        const std = math.std(rawData);
        processedData = rawData.map(x => (x - mean) / std);
    } 
    else if (method === 'l2') {
        // L2正規化: x / sqrt(sum(x_i^2))
        const norm = math.norm(rawData); // ベクトルの長さを計算
        processedData = rawData.map(x => x / norm);
    }

    displayResults(rawData, processedData);
    updateChart(rawData, processedData);
}

function displayResults(raw, processed) {
    const tbody = document.getElementById('resultBody');
    tbody.innerHTML = '';
    raw.forEach((val, i) => {
        const row = `<tr><td>${val}</td><td><strong>${processed[i].toFixed(4)}</strong></td></tr>`;
        tbody.innerHTML += row;
    });
    document.getElementById('resultArea').style.display = 'block';
}

function updateChart(raw, processed) {
    const ctx = document.getElementById('myChart').getContext('2d');
    if (chartInstance) chartInstance.destroy();

    chartInstance = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: raw.map((_, i) => `Item ${i + 1}`),
            datasets: [{
                label: '元の値',
                data: raw,
                backgroundColor: '#dee2e6',
                yAxisID: 'y',
            }, {
                label: '正規化後の値',
                data: processed,
                backgroundColor: '#007bff',
                yAxisID: 'y1',
            }]
        },
        options: {
            responsive: true,
            scales: {
                y: { type: 'linear', position: 'left', title: { display: true, text: 'Original Scale' } },
                y1: { type: 'linear', position: 'right', grid: { drawOnChartArea: false }, title: { display: true, text: 'Normalized Scale' } }
            }
        }
    });
}
</script>

</body>
</html>

今回解説したアルゴリズムの選択が、データ分析の精度を大きく左右する第一歩となります。

セイ・コンサルティング・グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
海外放浪の末、2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。