rescale

2025-06-06

データのリスケールとは、データの範囲(最小値と最大値)や分布を変更して、特定の目的に適合させる処理のことです。これにはいくつかの一般的な方法があります。

0から1の範囲へのリスケール(Min-Maxスケーリング)

これは最も一般的なリスケール方法の一つで、データを0から1の間に収めます。 計算式は以下のようになります。

Xscaled​=Xmax​−Xmin​X−Xmin​​

ここで、

  • Xmax​: データの最大値
  • Xmin​: データの最小値
  • X: 元のデータ
  • Xscaled​: スケールされたデータ

Octaveでの実装例:

% サンプルデータ
data = [10, 20, 30, 40, 50];

% 最小値と最大値を計算
data_min = min(data);
data_max = max(data);

% 0-1にリスケール
rescaled_data_0_1 = (data - data_min) / (data_max - data_min);

disp("元のデータ:");
disp(data);
disp("0-1にリスケールされたデータ:");
disp(rescaled_data_0_1);

特定の範囲へのリスケール

データを0から1の範囲ではなく、例えば-1から1の範囲や、任意の [A,B] の範囲にリスケールすることもできます。

[A,B] の範囲へのリスケール式:

Xscaled​=A+(X−Xmin​)Xmax​−Xmin​B−A​

Octaveでの実装例(-1から1の範囲):

% サンプルデータ
data = [10, 20, 30, 40, 50];

% 最小値と最大値を計算
data_min = min(data);
data_max = max(data);

% 目標とする最小値と最大値
target_min = -1;
target_max = 1;

% -1から1にリスケール
rescaled_data_neg1_1 = target_min + (data - data_min) * (target_max - target_min) / (data_max - data_min);

disp("-1から1にリスケールされたデータ:");
disp(rescaled_data_neg1_1);

標準化(Standardization / Z-score normalization)

これはリスケールとは少し異なりますが、データのスケールを変更する一般的な方法です。データを平均が0、標準偏差が1になるように変換します。

計算式:

Xstandardized​=σX−μ​

  • σ: データの標準偏差
  • μ: データの平均
  • X: 元のデータ
  • Xstandardized​: 標準化されたデータ
% サンプルデータ
data = [10, 20, 30, 40, 50];

% 平均と標準偏差を計算
data_mean = mean(data);
data_std = std(data);

% 標準化
standardized_data = (data - data_mean) / data_std;

disp("標準化されたデータ:");
disp(standardized_data);
  • データの可視化
    データを特定の範囲に収めることで、グラフなどでの可視化がしやすくなります。
  • 外れ値の影響軽減
    Min-Maxスケーリングの場合、大きな外れ値があると他のデータが0-1の非常に狭い範囲に押し込められてしまうことがあります。その場合、標準化の方が適している場合もあります。
  • 比較可能性の確保
    異なる単位やスケールを持つデータを比較可能にするため。例えば、ある特徴量が「年齢」(0-100)で、別の特徴量が「収入」(0-1000万円)である場合、そのままでは収入の方がモデルに与える影響が大きくなりすぎることがあります。
  • 機械学習アルゴリズムの性能向上
    多くの機械学習アルゴリズム(特に勾配降下法を用いるもの、例えばニューラルネットワークやSVM)は、入力特徴量のスケールが大きく異なる場合にうまく機能しないことがあります。リスケールすることで、これらのアルゴリズムの収束を速め、性能を向上させることができます。


ゼロ除算エラー(Division by Zero)

エラーの状況
最もよくあるエラーの一つです。Min-Maxスケーリングの式は Xscaled​=Xmax​−Xmin​X−Xmin​ですが、もしデータセット内のすべての値が同じ場合、Xmax​−Xminが0になり、ゼロ除算エラーが発生します。

エラーメッセージ例
error: division by zero

トラブルシューティング

  • 条件分岐の追加
    0除算を避けるために、分母が非常に小さい値(例えば、浮動小数点数の許容誤差範囲内)またはゼロである場合に特別な処理を行うコードを追加します。
  • データの確認
    リスケールしようとしているデータが、すべての要素で同じ値になっていないかを確認します。例えば、data = [5, 5, 5, 5] のようなデータの場合、このエラーが発生します。

解決策の例

data = [5, 5, 5, 5]; % すべて同じ値のデータ

data_min = min(data);
data_max = max(data);

if (data_max - data_min) == 0
    % 全ての要素が同じ値なので、リスケールしても値は変わらない
    rescaled_data = zeros(size(data)); % あるいは、元のデータをそのまま使う
    disp("データがすべて同じ値なので、リスケール処理は行いませんでした(またはゼロに設定)。");
else
    rescaled_data = (data - data_min) / (data_max - data_min);
end

disp(rescaled_data);

あるいは、非常に小さい許容誤差 epsilon を設定して比較する方法もあります。

epsilon = 1e-9; % 非常に小さい値

if abs(data_max - data_min) < epsilon
    rescaled_data = zeros(size(data)); % または元のデータをそのまま
    disp("データ範囲が極めて狭いため、リスケールは行いませんでした。");
else
    rescaled_data = (data - data_min) / (data_max - data_min);
end

データ型に関するエラー(型変換の誤り)

エラーの状況
Octaveは通常、数値演算において柔軟ですが、異なるデータ型(例えば、整数型と浮動小数点型、あるいは文字列)が混在している場合や、特定の関数が期待するデータ型と異なる場合に問題が発生することがあります。特に、画像処理などでuint8などの整数型データを扱う際に、意図しない丸めやクリッピングが発生することがあります。

エラーメッセージ例
特定のメッセージは出にくいかもしれませんが、結果が期待と異なる、または不正な操作として検出されることがあります。

トラブルシューティング

  • 明示的な型変換
    必要に応じて、double() 関数などを使ってデータを明示的に浮動小数点型に変換します。
  • データの確認
    リスケールする前に、class(data)whos data を使ってデータの型を確認します。

解決策の例

% 0から255の整数値の画像データのようなもの
img_data_uint8 = uint8([10, 50, 100, 200, 250]);

% そのまま計算すると、uint8の範囲で丸められる可能性がある
% 例えば、計算結果が負になる場合や255を超える場合に問題
% rescaled_img_uint8 = (img_data_uint8 - min(img_data_uint8)) / (max(img_data_uint8) - min(img_data_uint8)); % これだと型エラーや意図しない結果

% まずdouble型に変換してからリスケール
img_data_double = double(img_data_uint8);
rescaled_img_double = (img_data_double - min(img_data_double)) / (max(img_data_double) - min(img_data_double));

disp("元のuint8データ:");
disp(img_data_uint8);
disp("doubleに変換後、リスケールされたデータ:");
disp(rescaled_img_double);

% 必要であれば、最終的にuint8に戻す(その際に0-1の範囲から0-255などに再変換が必要)
% rescaled_img_uint8_final = uint8(rescaled_img_double * 255);

NaN (Not-a-Number) や Inf (Infinity) の混入

エラーの状況
データにNaN(欠損値など)やInf(無限大)が含まれている場合、min()max() 関数が正しく機能しないか、リスケール後の結果が全てNaNになることがあります。

エラーメッセージ例
明確なエラーメッセージが出ないことが多く、結果がNaNだらけになることで気づくことが多いです。

トラブルシューティング

  • 欠損値の処理
    リスケールする前に、NaNInfを適切に処理します。
    • 除外
      data(~isnan(data)) のようにして、NaNを含む要素を除外する。
    • 補完
      平均値、中央値、または他の方法でNaNを補完する。
    • 特定の値を割り当てる
      NaNを0や特定の固定値に置き換える。
  • データの確認
    any(isnan(data))any(isinf(data)) を使って、データにNaNInfが含まれていないかを確認します。

解決策の例

data_with_nan = [10, 20, NaN, 40, 50];

% NaNを除外してリスケール
clean_data = data_with_nan(~isnan(data_with_nan));

if isempty(clean_data)
    disp("有効なデータがありません。");
else
    data_min = min(clean_data);
    data_max = max(clean_data);

    if (data_max - data_min) == 0
        rescaled_data = zeros(size(clean_data));
    else
        rescaled_data = (clean_data - data_min) / (data_max - data_min);
    end
    disp("NaNを除外してリスケールされたデータ:");
    disp(rescaled_data);
end

% またはNaNを平均値で補完する例
data_with_nan_imputed = data_with_nan;
nan_indices = isnan(data_with_nan_imputed);
data_with_nan_imputed(nan_indices) = mean(data_with_nan_imputed(~nan_indices));

data_min_imputed = min(data_with_nan_imputed);
data_max_imputed = max(data_with_nan_imputed);

if (data_max_imputed - data_min_imputed) == 0
    rescaled_data_imputed = zeros(size(data_with_nan_imputed));
else
    rescaled_data_imputed = (data_with_nan_imputed - data_min_imputed) / (data_max_imputed - data_min_imputed);
end
disp("平均値で補完後、リスケールされたデータ:");
disp(rescaled_data_imputed);

浮動小数点数演算の精度問題

エラーの状況
非常に小さい値や非常に大きい値を扱う場合、または多数の浮動小数点数演算を連続して行う場合、計算の丸め誤差により、期待通りの厳密な0や1が得られないことがあります。例えば、Min-Maxスケーリングで最小値が厳密に0にならない(1e-16のような非常に小さい値になる)ことがあります。

エラーメッセージ例
通常、エラーメッセージは出ませんが、デバッグ時に期待値とのわずかな差異が見られます。

トラブルシューティング

  • データのスケーリング順序の検討
    複雑な計算の場合、計算順序を工夫することで精度が改善されることがあります。
  • 許容誤差(Tolerance)の使用
    厳密な等価性チェックではなく、許容誤差を用いた範囲チェックを行います。

解決策の例

data = [1, 1.0000000000000001, 2]; % 微妙な違いを持つデータ

data_min = min(data);
data_max = max(data);

rescaled_data = (data - data_min) / (data_max - data_min);

disp("リスケールされたデータ:");
disp(rescaled_data);

% 最小値が厳密に0かどうかを確認する代わりに、許容誤差を使う
tolerance = 1e-10; % 許容誤差を設定
if abs(min(rescaled_data)) < tolerance
    disp("最小値は実質的にゼロです。");
else
    disp("最小値はゼロではありません。");
end

配列の次元の不一致

エラーの状況
データが単一のベクトルではなく、行列や多次元配列の場合、min()max()関数がデフォルトで列ごとに(または指定された次元で)最小値/最大値を計算するため、意図しない結果になることがあります。データ全体で一貫したリスケールを行いたい場合、min(data(:))のようにすべての要素を考慮する必要があります。

エラーメッセージ例
error: A(I): index out of bounds; value 0 out of bound 1 (インデックスの誤り) error: nonconformant arguments (op1 is 1xN, op2 is 1xM) (行列の次元不一致) あるいは、計算はされるものの、期待する結果と異なる。

トラブルシューティング

  • 次元の指定
    特定の次元(行ごと、列ごとなど)でリスケールしたい場合は、min(data, [], dim) のようにdim引数を指定します。
  • min(data(:)) の使用
    行列全体で最小値/最大値を計算したい場合は、data(:) を使ってデータを一次元ベクトルに平坦化してからmin()/max()を適用します。
matrix_data = [1, 2, 3; 4, 5, 6; 7, 8, 9];

% 誤ったリスケール(列ごとにmin/maxが計算されてしまう)
% rescaled_matrix_wrong = (matrix_data - min(matrix_data)) ./ (max(matrix_data) - min(matrix_data)); % これだと次元が合わないか、意図しない結果

% 行列全体でmin/maxを計算してリスケール
matrix_min = min(matrix_data(:));
matrix_max = max(matrix_data(:));

if (matrix_max - matrix_min) == 0
    rescaled_matrix = zeros(size(matrix_data));
else
    rescaled_matrix = (matrix_data - matrix_min) / (matrix_max - matrix_min);
end

disp("元の行列データ:");
disp(matrix_data);
disp("行列全体でリスケールされたデータ:");
disp(rescaled_matrix);
  • エラーメッセージをよく読む
    Octaveのエラーメッセージは、問題の箇所や種類を特定するのに役立ちます。
  • Octaveのドキュメントを参照
    使用している関数(min, max, mean, stdなど)のドキュメントを確認し、その挙動を理解しておきましょう。
  • 中間結果の表示
    計算の途中で各変数の値(data_mindata_maxdenominatorなど)を表示して、どこで問題が発生しているかを特定します。disp()fprintf()を活用しましょう。
  • 小さなデータセットでテスト
    まずは数個の要素を持つ小さな配列でリスケール処理をテストし、結果が期待通りかを確認します。


Min-Max スケーリング(0-1 へのリスケール)

最も一般的で、データを [0,1] の範囲に収める方法です。 目的
データの最小値を0、最大値を1に正規化し、他の値はその間の比率で配置されます。

数学的表現
Xscaled​=Xmax​−Xmin​X−Xmin​​

Octave コード例

% === Min-Max スケーリングの関数定義 ===
% この関数は、入力ベクトル/行列 data を 0-1 の範囲にリスケールします。
function rescaled_data = min_max_scale(data)
    % データの最小値と最大値を計算
    % data(:) は、行列の場合でもすべての要素を単一の列ベクトルとして扱います。
    data_min = min(data(:));
    data_max = max(data(:));

    % ゼロ除算の回避: 全てのデータが同じ値の場合
    if (data_max - data_min) == 0
        % この場合、全ての要素が同じ値なので、リスケールしても意味がない
        % 通常は0で埋めるか、元のデータをそのまま返す
        rescaled_data = zeros(size(data));
        fprintf('Warning: All data points are identical. Rescaled to zeros.\n');
    else
        % リスケールを実行
        rescaled_data = (data - data_min) / (data_max - data_min);
    end
end

% === 使用例 1: ベクトルデータ ===
fprintf('--- 使用例 1: ベクトルデータ ---\n');
data_vector = [10, 25, 5, 40, 15];
rescaled_vector = min_max_scale(data_vector);

disp('元のベクトルデータ:');
disp(data_vector);
disp('0-1 にリスケールされたベクトルデータ:');
disp(rescaled_vector);

% 検証 (最小値が0に、最大値が1に近づくことを確認)
fprintf('スケーリング後の最小値: %f\n', min(rescaled_vector(:)));
fprintf('スケーリング後の最大値: %f\n', max(rescaled_vector(:)));

% === 使用例 2: 行列データ ===
fprintf('\n--- 使用例 2: 行列データ ---\n');
data_matrix = [
    100, 200;
    50,  300;
    150, 250
];
rescaled_matrix = min_max_scale(data_matrix);

disp('元の行列データ:');
disp(data_matrix);
disp('0-1 にリスケールされた行列データ:');
disp(rescaled_matrix);

% === 使用例 3: 全てのデータが同じ値の場合 ===
fprintf('\n--- 使用例 3: 全てのデータが同じ値の場合 ---\n');
data_same = [7, 7, 7, 7];
rescaled_same = min_max_scale(data_same);
disp('元のデータ:');
disp(data_same);
disp('リスケールされたデータ (全ての値が同じ):');
disp(rescaled_same);

特定の範囲へのリスケール ([A,B] へのリスケール)

データを任意の [A,B] の範囲に収める方法です。 目的
データを特定のカスタム範囲に正規化します。例えば、画像のピクセル値を [0,255] の範囲に変換する場合などに便利です。

数学的表現
Xscaled​=A+(X−Xmin​)Xmax​−Xmin​B−A​

Octave コード例

% === 特定範囲へのスケーリング関数定義 ===
% この関数は、入力ベクトル/行列 data を target_min から target_max の範囲にリスケールします。
function rescaled_data = custom_range_scale(data, target_min, target_max)
    data_min = min(data(:));
    data_max = max(data(:));

    if (data_max - data_min) == 0
        % 全てのデータが同じ値の場合、ターゲット範囲の中央値で埋めるか、
        % target_min, target_max のどちらかの値に設定する
        rescaled_data = ones(size(data)) * (target_min + target_max) / 2;
        fprintf('Warning: All data points are identical. Rescaled to target range midpoint.\n');
    else
        % リスケールを実行
        rescaled_data = target_min + (data - data_min) * (target_max - target_min) / (data_max - data_min);
    end
end

% === 使用例 1: -1 から 1 へ ===
fprintf('--- 使用例 1: -1 から 1 へ ---\n');
data_example = [10, 20, 30, 40, 50];
rescaled_neg1_1 = custom_range_scale(data_example, -1, 1);

disp('元のデータ:');
disp(data_example);
disp('-1 から 1 にリスケールされたデータ:');
disp(rescaled_neg1_1);

% 検証
fprintf('スケーリング後の最小値: %f\n', min(rescaled_neg1_1(:)));
fprintf('スケーリング後の最大値: %f\n', max(rescaled_neg1_1(:)));

% === 使用例 2: 0 から 255 へ (画像ピクセル値など) ===
fprintf('\n--- 使用例 2: 0 から 255 へ ---\n');
data_image_values = [10, 80, 150, 200, 250]; % 元のピクセル値
rescaled_0_255 = custom_range_scale(data_image_values, 0, 255);

disp('元の画像値:');
disp(data_image_values);
disp('0 から 255 にリスケールされた画像値:');
disp(rescaled_0_255); % 結果は浮動小数点数になる点に注意

% 必要であれば整数型に変換
% rescaled_0_255_uint8 = uint8(round(rescaled_0_255));
% disp('Uint8 に変換された画像値:');
% disp(rescaled_0_255_uint8);

標準化 (Standardization / Z-score Normalization)

データを平均が0、標準偏差が1になるように変換する方法です。 目的
データの分布を正規分布に近づけ、外れ値の影響を受けにくくします。機械学習アルゴリズム(特に距離ベースのアルゴリズムや勾配降下法を用いるもの)でよく用いられます。

数学的表現
Xstandardized​=σX−μ​ ここで、μ はデータの平均、σ はデータの標準偏差です。

% === 標準化の関数定義 ===
% この関数は、入力ベクトル/行列 data を平均0、標準偏差1に標準化します。
function standardized_data = standardize_data(data)
    % データの平均と標準偏差を計算
    data_mean = mean(data(:));
    data_std = std(data(:));

    % 標準偏差が0の場合(全てのデータが同じ値の場合)
    if data_std == 0
        standardized_data = zeros(size(data));
        fprintf('Warning: Standard deviation is zero. Data standardized to zeros.\n');
    else
        % 標準化を実行
        standardized_data = (data - data_mean) / data_std;
    end
end

% === 使用例 1: ベクトルデータ ===
fprintf('--- 使用例 1: ベクトルデータ ---\n');
data_vector_std = [100, 110, 90, 120, 80];
standardized_vector = standardize_data(data_vector_std);

disp('元のベクトルデータ:');
disp(data_vector_std);
disp('標準化されたベクトルデータ:');
disp(standardized_vector);

% 検証
fprintf('標準化後の平均値: %f\n', mean(standardized_vector(:)));
fprintf('標準化後の標準偏差: %f\n', std(standardized_vector(:)));

% === 使用例 2: 行列データ ===
fprintf('\n--- 使用例 2: 行列データ ---\n');
data_matrix_std = [
    10, 20, 30;
    15, 25, 35;
    12, 22, 32
];
standardized_matrix = standardize_data(data_matrix_std);

disp('元の行列データ:');
disp(data_matrix_std);
disp('標準化された行列データ:');
disp(standardized_matrix);

% === 使用例 3: 全てのデータが同じ値の場合 ===
fprintf('\n--- 使用例 3: 全てのデータが同じ値の場合 ---\n');
data_same_std = [5, 5, 5, 5];
standardized_same = standardize_data(data_same_std);
disp('元のデータ:');
disp(data_same_std);
disp('標準化されたデータ (全ての値が同じ):');
disp(standardized_same);
  • 検証
    min()max(), mean(), std() 関数を使って、リスケール後のデータが期待通りの範囲や統計量になっているかを確認する行を含めています。これはデバッグや理解に役立ちます。
  • 関数化
    リスケール処理を関数として定義することで、コードの再利用性が高まり、可読性も向上します。
  • ゼロ除算の回避
    いずれのリスケール方法でも、分母がゼロになるケース(例えば、Min-Maxスケーリングで data_max - data_min == 0 の場合、または標準化で data_std == 0 の場合)を考慮し、適切な警告や代替処理を行うようにしています。これは頑健なコードを書く上で非常に重要です。
  • data(:) の使用
    min(data(:))max(data(:)) を使うことで、data がベクトルでも行列でも、その中のすべての要素の最小値や最大値を計算できます。これは、データセット全体で一貫したスケーリングを行う場合に特に重要です。


以下に、Octaveで利用できる代替のリスケール(または関連する正規化)方法とそのプログラミング例を説明します。

ロバストスケーリング (Robust Scaling)

目的
Min-Maxスケーリングや標準化は、データに極端な外れ値が含まれる場合に大きく影響を受け、ほとんどのデータポイントが非常に狭い範囲に押し込められてしまうことがあります。ロバストスケーリングは、中央値(median)と四分位範囲(IQR: Interquartile Range)を用いることで、外れ値の影響を軽減し、より堅牢なスケーリングを提供します。

数学的表現
Xscaled​=IQR(X)X−Median(X)​ ここで、Median(X)はデータの中央値、IQR(X)は第3四分位数と第1四分位数の差(Q3−Q1)です。

Octave コード例

% === ロバストスケーリングの関数定義 ===
% この関数は、入力ベクトル/行列 data を中央値0、IQR=1 にリスケールします。
function rescaled_data = robust_scale(data)
    % データの一次元化
    data_flat = data(:);

    % 中央値を計算
    data_median = median(data_flat);

    % 四分位範囲 (IQR) を計算
    % quantile関数はパーセンタイルを計算します。
    % 25パーセンタイルがQ1、75パーセンタイルがQ3
    Q1 = quantile(data_flat, 0.25);
    Q3 = quantile(data_flat, 0.75);
    data_iqr = Q3 - Q1;

    % ゼロ除算の回避
    if data_iqr == 0
        rescaled_data = zeros(size(data));
        fprintf('Warning: Interquartile Range is zero. Data rescaled to zeros.\n');
    else
        % リスケールを実行
        rescaled_data = (data - data_median) / data_iqr;
    end
end

% === 使用例 ===
fprintf('--- ロバストスケーリング --- \n');
data_with_outlier = [10, 20, 30, 40, 1000]; % 1000が外れ値
rescaled_robust = robust_scale(data_with_outlier);

disp('元のデータ (外れ値あり):');
disp(data_with_outlier);
disp('ロバストスケーリング後のデータ:');
disp(rescaled_robust);

% Min-Maxスケーリングと比較
rescaled_min_max = (data_with_outlier - min(data_with_outlier)) / (max(data_with_outlier) - min(data_with_outlier));
disp('Min-Max スケーリング後のデータ (比較用):');
disp(rescaled_min_max);

% ロバストスケーリングでは、外れ値が他のデータポイントを極端に圧縮しないことが見て取れます。

ベクトルノルムによる正規化 (Normalization by Vector Norm)

目的
ベクトル(行または列)の長さ(ノルム)が1になるようにデータをスケーリングします。これは、データの方向が重要で、大きさ(マグニチュード)が重要でない場合に特に有用です。例えば、テキスト分類における単語出現頻度ベクトルの正規化や、コサイン類似度の計算などで使われます。

数学的表現
L2ノルム正規化 (Euclidean Norm): Xnormalized​=∥X∥2​X​ ここで、∥X∥2​=∑xi2​です。

Octave コード例

% === L2 ノルム正規化の関数定義 ===
% この関数は、入力ベクトル/行列 data を L2 ノルムが 1 になるように正規化します。
% 行列の場合、デフォルトでは列ごとに正規化します。
function normalized_data = l2_normalize(data)
    % ノルムを計算 (列ごとに)
    % Octave の norm 関数はデフォルトで L2 ノルムを計算します
    % norm(data) は行列全体のノルムを計算
    % norm(data, 'fro') はフロベニウスノルム (全要素の二乗和の平方根)
    % sqrt(sum(data.^2)) は列ごとのノルムを計算
    
    % 行列全体で正規化する場合 (全ての要素を平坦化)
    data_norm = norm(data(:));

    if data_norm == 0
        normalized_data = zeros(size(data));
        fprintf('Warning: Norm is zero. Data normalized to zeros.\n');
    else
        normalized_data = data / data_norm;
    end
end

% === 使用例 1: ベクトルデータ ===
fprintf('--- L2 ノルム正規化 (ベクトル) ---\n');
data_vec_norm = [3, 4]; % ユークリッド距離は sqrt(3^2 + 4^2) = 5
normalized_vec = l2_normalize(data_vec_norm);

disp('元のベクトル:');
disp(data_vec_norm);
disp('L2 正規化されたベクトル:');
disp(normalized_vec);
fprintf('正規化後のノルム: %f\n', norm(normalized_vec));

% === 使用例 2: 行列データ (列ごとに正規化) ===
% 通常、機械学習では特徴量(列)ごとに正規化することが多い
fprintf('\n--- L2 ノルム正規化 (行列、列ごと) ---\n');
data_matrix_norm = [
    1, 2;
    3, 4;
    5, 6
];

% 列ごとにノルムを計算し、正規化する関数
function normalized_cols = l2_normalize_columns(matrix)
    normalized_cols = zeros(size(matrix));
    for i = 1:columns(matrix)
        col = matrix(:, i);
        col_norm = norm(col);
        if col_norm == 0
            normalized_cols(:, i) = zeros(rows(matrix), 1);
        else
            normalized_cols(:, i) = col / col_norm;
        end
    end
end

normalized_matrix_cols = l2_normalize_columns(data_matrix_norm);

disp('元の行列:');
disp(data_matrix_norm);
disp('L2 正規化された行列 (列ごと):');
disp(normalized_matrix_cols);
fprintf('1列目の正規化後のノルム: %f\n', norm(normalized_matrix_cols(:,1)));
fprintf('2列目の正規化後のノルム: %f\n', norm(normalized_matrix_cols(:,2)));

norm(data(:))を使うと行列全体で計算し、norm(data)とすると行列の最大特異値を返します。列ごとの正規化はループで実装するのが一般的です。

ロギング変換 (Log Transformation)

目的
非常に広い範囲に分布するデータ(例えば、収入や人口など)や、右に大きく歪んだ分布を持つデータ(指数分布のようなもの)をより正規分布に近い形に変換し、スケールを圧縮します。これは、線形モデルの前提を満たすためや、可視化を容易にするためによく用いられます。

数学的表現
Xtransformed​=log(X) 一般的には自然対数(logまたはlog_e)や常用対数(log10)が使われます。データが0を含む場合は、log(X + 1) のように小さな定数を加えることが一般的です。

Octave コード例

% === ロギング変換の関数定義 ===
% この関数は、入力データにロギング変換を適用します。
% 0や負の値に対応するため、log(x+1)を使用します。
function transformed_data = log_transform(data)
    % 負の値やゼロがある場合に備えて1を加える
    % データが負の値を含む場合は、この変換は適しません
    if any(data(:) < 0)
        fprintf('Warning: Data contains negative values. Log transformation may not be appropriate.\n');
    end
    transformed_data = log(data + 1); % 自然対数 (ln)
end

% === 使用例 ===
fprintf('--- ロギング変換 ---\n');
data_skewed = [1, 5, 10, 50, 100, 1000, 10000];
transformed_log = log_transform(data_skewed);

disp('元の歪んだデータ:');
disp(data_skewed);
disp('ロギング変換後のデータ:');
disp(transformed_log);

% ゼロを含む場合の例
data_with_zero = [0, 1, 10, 100];
transformed_log_zero = log_transform(data_with_zero);
disp('ゼロを含むデータ:');
disp(data_with_zero);
disp('ロギング変換後のデータ (ゼロ対応):');
disp(transformed_log_zero);

目的
ロギング変換を一般化したもので、データの分布をより正規分布に近づけるために用いられます。最適な変換パラメータ λ をデータから学習します。正のデータにのみ適用可能です。

数学的表現
X(λ)={λXλ−1​log(X)​if λ=0if λ=0​

Box-Cox変換は、一般的に最適な λ を見つけるための統計的な手法(最尤推定など)が必要です。Octaveには組み込みのBox-Cox変換関数はありませんが、統計ツールボックスなどを利用するか、自分で実装することができます。ここでは実装例は省略しますが、概念として重要な代替手段です。

  • 特徴量ハッシュ (Feature Hashing)
    高次元のカテゴリカルデータを低次元の固定サイズのベクトルに変換する手法。厳密な意味での「リスケール」とは異なりますが、データのスケールを調整し、メモリ効率を高めるための代替手段として使われることがあります。
  • 画像のピクセル値スケーリング
    画像のピクセル値(通常 0-255)を機械学習モデルの入力に適した 0-1 の浮動小数点値に変換する場合、単に pixel_value / 255.0 のように最大値で割るだけの場合も多いです。