パンダデータフレームの列を正規化する


227

各列の値の範囲が異なるパンダのデータフレームがあります。例えば:

df:

A     B   C
1000  10  0.5
765   5   0.35
800   7   0.09

各データが0と1の間であるこのデータフレームの列をどのように正規化できるか考えていますか?

私の望ましい出力は:

A     B    C
1     1    1
0.765 0.5  0.7
0.8   0.7  0.18(which is 0.09/0.5)

1
適用関数があります。たとえば、frame.apply(f、axis = 1)ここで、fは行で何かを実行する関数です...
tschm

1
scikit-learnのドキュメントでは、「個々のサンプルをスケーリングして単位ノルムを持つようにするプロセス」と定義しているため(つまり、正しく取得した場合は行ごとに)、正規化は最も適切な表現ではない可能性があります。
Skippy le Grand Gourou

取得できません。min_maxスケーリングが正規化と見なされるのはなぜですか。通常は平均ゼロ、分散1の正規分布の意味で意味を持つようになった
オーバーフロー警察

2020年以降にこの質問にアクセスしている場合は、@ Poudelの回答を見てください。パンダとsklearnを使用すると、正規化の答えが異なります。
Bhishan Poudel

@Poudelはこれはddof議論によるものですか?
fffrost

回答:


223

パッケージsklearnとそれに関連する前処理ユーティリティを使用して、データを正規化できます。

import pandas as pd
from sklearn import preprocessing

x = df.values #returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
df = pd.DataFrame(x_scaled)

詳細については、データの前処理に関するscikit-learnのドキュメントを参照してください。


46
これで列名が取り除かれると思います。これは、opが最初からデータフレームを使用している理由の1つかもしれません。
pietz

47
これは、最初に転置しない限り、列ではなく行を正規化します。Qが要求することを行うには:pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)
ホブ

26
@pietzは列名を保持します。この投稿を参照してください。基本的に最後の行をに置き換えますdf=pandas.DataFrame(x_scaled, columns=df.columns)
ijoseph '26 / 06/26

5
@hobs不正解です。サンドマンのコードは、列ごとおよび列ごとに正規化します。転置すると間違った結果になります。
petezurich

8
@petezurich SandmanまたはPraveenがコードを修正したようです。残念ながら、コメントを修正することはできません;)
ホブ

398

パンダを使用する簡単な方法:(ここでは平均正規化を使用したい)

normalized_df=(df-df.mean())/df.std()

min-max正規化を使用するには:

normalized_df=(df-df.min())/(df.max()-df.min())

編集:いくつかの懸念に対処するには、Pandasが上記のコードでコロン単位の関数を自動的に適用することを言う必要があります。


16
私はこれが好きです。短く、表現力があり、ヘッダー情報を保持します。しかし、分母の分も減算する必要があると思います。
ピエツ2017年

6
私はそれが間違っているとは思いません。私にとって美しく機能します-これが機能するためにmean()とstd()がデータフレームを返す必要はないと思います。エラーメッセージは、それらがデータフレームでないことが問題であることを示唆していません。
Strandtasche 2018年

24
これは列ごとの正規化ではありません。これはマトリックス全体を正規化するため、間違った結果が得られます。
Nguai al

6
美しくも私のために働きました。@Nguaialあなたはこれを派手な行列で試そうとしているかもしれません、その場合、結果はあなたが言ったものになるでしょう。ただし、Pandasデータフレームの場合、min、max、...メジャーはデフォルトで列ごとに適用されます。
補助

1
私もこれが好きです
Isaac Sim

51

この投稿に基づく:https : //stats.stackexchange.com/questions/70801/how-to-normalize-data-to-0-1-range

次のことができます。

def normalize(df):
    result = df.copy()
    for feature_name in df.columns:
        max_value = df[feature_name].max()
        min_value = df[feature_name].min()
        result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value)
    return result

値が負か正かを心配する必要はありません。そして、値は0と1の間でうまく分散する必要があります。


8
最小値と最大値が同じで、分母が0であり、NaN値を取得する場合は注意してください。
Hrushikesh Dhumal

36

あなたの問題は実際には列に作用する単純な変換です:

def f(s):
    return s/s.max()

frame.apply(f, axis=0)

またはさらに簡潔:

   frame.apply(lambda x: x/x.max(), axis=0)

2
lambda1は最高です:-)
アブShoeb

4
問題は列ごとの正規化なので、これはaxis = 1であるはずではありませんか?
グアイアル

いいえ、ドキュメントから:axis [...] 0 or 'index': apply function to each column。デフォルトは実際axis=0にはこのワンライナーをさらに短く書くことができるようになっています:-)ありがとう@tschm。
jorijnsmit

30

sklearnパッケージを使用する場合は、次のようにパンダを使用して、列とインデックスの名前を維持できますloc

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler() 
scaled_values = scaler.fit_transform(df) 
df.loc[:,:] = scaled_values

27

シンプルは美しい:

df["A"] = df["A"] / df["A"].max()
df["B"] = df["B"] / df["B"].max()
df["C"] = df["C"] / df["C"].max()

素晴らしい、そして私の意見では最良の解決策です!
Maciej A. Bednarz

6
OPは[0..1]の範囲を要求し、このソリューションは[-1..1]の範囲にスケーリングされることに注意してください。これを配列[-10、10]で試してください。
Alexander Sosnovshchenko

3
@AlexanderSosnovshchenko本当にそうではありません。バジルムーサは、OPの行列が常に負ではないと想定しているため、このソリューションを提供しました。一部の列に負のエントリがある場合、このコードは[-1,1]の範囲に正規化されません。配列[-5、10]で試してください。負の値を持つ[0,1]に正規化するための正しい方法は、シーナの答えで与えられたdf["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())
facuq

シンプルかつ明示的
joshi123

おそらくさらに簡単です:df /= df.max()-目標がすべての列を個別に正規化することであると仮定します。
n1k31t4

24

正規化する列のリストを作成できます

column_names_to_normalize = ['A', 'E', 'G', 'sadasdsd', 'lol']
x = df[column_names_to_normalize].values
x_scaled = min_max_scaler.fit_transform(x)
df_temp = pd.DataFrame(x_scaled, columns=column_names_to_normalize, index = df.index)
df[column_names_to_normalize] = df_temp

Pandas Dataframeは、必要な列でのみ正規化されます


ただし反対が必要な場合は、正規化しない列のリストを選択し、すべての列のリストを作成して、不要な列を削除することができます

column_names_to_not_normalize = ['B', 'J', 'K']
column_names_to_normalize = [x for x in list(df) if x not in column_names_to_not_normalize ]

11

パンダでそれを行うより良い方法はちょうどだと思います

df = df/df.max().astype(np.float64)

編集データフレームに負の数が存在する場合は、代わりに使用する必要があります

df = df/df.loc[df.abs().idxmax()].astype(np.float64)

1
列のすべての値がゼロの場合、これは機能しません
ahajib

minが0でない限り、最大で現在の値を分割することは、あなたに正しい正規化を与えることはありません
pietzは

私は同意しますが、それはOTが求めていたものです(彼の例を参照)
Daniele

11

サンドマンとプラヴィーンによって与えられた解決策は非常にうまくいきます。データフレームの他の列にカテゴリ変数がある場合の唯一の問題は、このメソッドでいくつかの調整が必要になることです。

このタイプの問題に対する私の解決策は次のとおりです。

 from sklearn import preprocesing
 x = pd.concat([df.Numerical1, df.Numerical2,df.Numerical3])
 min_max_scaler = preprocessing.MinMaxScaler()
 x_scaled = min_max_scaler.fit_transform(x)
 x_new = pd.DataFrame(x_scaled)
 df = pd.concat([df.Categoricals,x_new])

2
インターネット上のほとんどの例は1つのスケーラーをすべての列に適用するため、この回答は役に立ちますが、これは実際には1つのスケーラー、たとえばMinMaxScalerがすべての列に適用されるべきではない状況に対処します。
デモンゴレム2018

10

Pythonでのさまざまな標準化の例。

参考として、このウィキペディアの記事をご覧くださいhttps : //en.wikipedia.org/wiki/Unbiased_estimation_of_standard_deviation

データの例

import pandas as pd
df = pd.DataFrame({
               'A':[1,2,3],
               'B':[100,300,500],
               'C':list('abc')
             })
print(df)
   A    B  C
0  1  100  a
1  2  300  b
2  3  500  c

パンダを使用した正規化(公平な推定値を提供)

正規化するときは、単純に平均を差し引き、標準偏差で割ります。

df.iloc[:,0:-1] = df.iloc[:,0:-1].apply(lambda x: (x-x.mean())/ x.std(), axis=0)
print(df)
     A    B  C
0 -1.0 -1.0  a
1  0.0  0.0  b
2  1.0  1.0  c

sklearnを使用した正規化(偏った推定値を与える、パンダとは異なる)

同じことをsklearnすると、異なる出力が得られます!

import pandas as pd

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()


df = pd.DataFrame({
               'A':[1,2,3],
               'B':[100,300,500],
               'C':list('abc')
             })
df.iloc[:,0:-1] = scaler.fit_transform(df.iloc[:,0:-1].to_numpy())
print(df)
          A         B  C
0 -1.224745 -1.224745  a
1  0.000000  0.000000  b
2  1.224745  1.224745  c

sklearnのバイアス推定は機械学習の能力を低下させますか?

番号。

sklearn.preprocessing.scaleの公式ドキュメントには、バイアス推定器を使用しても機械学習アルゴリズムのパフォーマンスに影響を与える可能性は低く、安全に使用できると記載されています。

From official documentation:
We use a biased estimator for the standard deviation,
equivalent to numpy.std(x, ddof=0). 
Note that the choice of ddof is unlikely to affect model performance.

MinMaxスケーリングはどうですか?

MinMaxスケーリングには標準偏差の計算はありません。したがって、パンダとscikit-learnの両方で結果は同じです。

import pandas as pd
df = pd.DataFrame({
               'A':[1,2,3],
               'B':[100,300,500],
             })
(df - df.min()) / (df.max() - df.min())
     A    B
0  0.0  0.0
1  0.5  0.5
2  1.0  1.0


# Using sklearn
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler() 
arr_scaled = scaler.fit_transform(df) 

print(arr_scaled)
[[0.  0. ]
 [0.5 0.5]
 [1.  1. ]]

df_scaled = pd.DataFrame(arr_scaled, columns=df.columns,index=df.index)
print(df_scaled)
     A    B
0  0.0  0.0
1  0.5  0.5
2  1.0  1.0

6

データラベルやカテゴリカラムが変更されない回帰タスクのように、一部の列は正規化され、他の列は変更されないようにする必要があるかもしれません。

features_to_normalize = ['A', 'B', 'C']
# could be ['A','B'] 

df[features_to_normalize] = df[features_to_normalize].apply(lambda x:(x-x.min()) / (x.max()-x.min()))

5

単純な数学だけです。答えは以下のように単純でなければなりません。

normed_df = (df - df.min()) / (df.max() - df.min())

2
def normalize(x):
    try:
        x = x/np.linalg.norm(x,ord=1)
        return x
    except :
        raise
data = pd.DataFrame.apply(data,normalize)

パンダのドキュメントから、DataFrame構造はそれ自体に操作(関数)を適用できます。

DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)

DataFrameの入力軸に沿って関数を適用します。関数に渡されるオブジェクトは、DataFrameのインデックス(axis = 0)または列(axis = 1)のいずれかのインデックスを持つSeriesオブジェクトです。戻り値の型は、渡された関数が集約するかどうか、またはDataFrameが空の場合はreduce引数によって異なります。

カスタム関数を適用してDataFrameを操作できます。


2
コードがOPの問題を解決する理由を説明すると、人々は単にコードをコピーするのではなく、戦略を適応できるようになります。良い答えを書くにはどうすればいいですか?を
T氏

2

次の関数は、Zスコアを計算します。

def standardization(dataset):
  """ Standardization of numeric fields, where all values will have mean of zero 
  and standard deviation of one. (z-score)

  Args:
    dataset: A `Pandas.Dataframe` 
  """
  dtypes = list(zip(dataset.dtypes.index, map(str, dataset.dtypes)))
  # Normalize numeric columns.
  for column, dtype in dtypes:
      if dtype == 'float32':
          dataset[column] -= dataset[column].mean()
          dataset[column] /= dataset[column].std()
  return dataset

2

これは、リスト内包表記を使用して列ごとに行う方法です。

[df[col].update((df[col] - df[col].min()) / (df[col].max() - df[col].min())) for col in df.columns]

1

次のように、pandas.DataFrame.transform 1関数を使用するだけです。

df.transform(lambda x: x/x.max())

すべての値が負の場合、このソリューションは機能しません。[-1、-2、-3]を検討してください。-1で除算すると、[1,2,3]になります。
Dave Liu


0

あなたはこれを一行で行うことができます

DF_test = DF_test.sub(DF_test.mean(axis=0), axis=1)/DF_test.mean(axis=0)

各列の平均をとり、それから各行からit(平均)を減算し(特定の列の平均はその行からのみ減算)、平均のみで除算します。最後に、得られるのは正規化されたデータセットです。


0

パンダはデフォルトで列ごとの正規化を行います。以下のコードを試してください。

X= pd.read_csv('.\\data.csv')
X = (X-X.min())/(X.max()-X.min())

出力値は0から1の範囲になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.