パンダのデータを正規化する


131

私がパンダのデータフレームを持っていると仮定しますdf

データフレームの列ごとの平均を計算します。

これは簡単:

df.apply(average) 

次に、列ごとの範囲max(col)-min(col)。これも簡単です。

df.apply(max) - df.apply(min)

次に、各要素について、その列の平均を減算し、その列の範囲で除算します。どうすればいいのかわかりません

ヘルプ/ポインタは大歓迎です。

回答:


225
In [92]: df
Out[92]:
           a         b          c         d
A  -0.488816  0.863769   4.325608 -4.721202
B -11.937097  2.993993 -12.916784 -1.086236
C  -5.569493  4.672679  -2.168464 -9.315900
D   8.892368  0.932785   4.535396  0.598124

In [93]: df_norm = (df - df.mean()) / (df.max() - df.min())

In [94]: df_norm
Out[94]:
          a         b         c         d
A  0.085789 -0.394348  0.337016 -0.109935
B -0.463830  0.164926 -0.650963  0.256714
C -0.158129  0.605652 -0.035090 -0.573389
D  0.536170 -0.376229  0.349037  0.426611

In [95]: df_norm.mean()
Out[95]:
a   -2.081668e-17
b    4.857226e-17
c    1.734723e-17
d   -1.040834e-17

In [96]: df_norm.max() - df_norm.min()
Out[96]:
a    1
b    1
c    1
d    1

サブセットを正規化したい場合、これを行う方法はありますか?その行Aを言いBます。これは、Cおよびとは別に正規化する、より大きなグループ化要素の一部ですD
Amyunimus

サブセットを選択し、以前と同様に計算します。データのインデックス付けと選択の方法については、pandas.pydata.org / pandas-docs / stable / indexing.htmlをご覧ください
Wouter Overmeire

17
値を0より大きくする必要がある場合:df_norm =(df-df.min())/(df.max()-df.min())
Dayvid Oliveira

1
最初の括弧内のdf.mean()ではなくdf_norm =(df-df.min())/(df.max()-df.min())である必要があります。0と1の間の値を取得するには
jnPy

2
データフレームの一部の列に文字列がある場合は、この回答を
netskink

73

sklearnライブラリのインポートを気にしない場合は、このブログで説明されている方法をお勧めします。

import pandas as pd
from sklearn import preprocessing

data = {'score': [234,24,14,27,-74,46,73,-18,59,160]}
cols = data.columns
df = pd.DataFrame(data)
df

min_max_scaler = preprocessing.MinMaxScaler()
np_scaled = min_max_scaler.fit_transform(df)
df_normalized = pd.DataFrame(np_scaled, columns = cols)
df_normalized

2
ブログ投稿へのリンクは無効です。機能しているものはありますか?
マート2016年

3
単位法線正規化データを作成するための対応するメソッドは、StandardScalerと呼ばれます。
abeboparebop 2017年

別の場所で同様の解決策を見つけました。問題は、np_scaledパーツで、2D配列を予期しているエラーを示していましたが、入力は1D配列であり、reshape(-1,1)を使用することをお勧めしました。形を変えるときにこれを解決する方法も考えられません。
デッドコード2017

使用するnumpy&sklearnのバージョンによっては警告が表示される場合がありますが、通常、これは機能するはずです np_scaled = min_max_scaler.fit_transform(df.score.astype(float).values.reshape(-1, 1))
Jaeyoung Chun

33

あなたはapplyこれに使用でき、それは少しすっきりしています:

import numpy as np
import pandas as pd

np.random.seed(1)

df = pd.DataFrame(np.random.randn(4,4)* 4 + 3)

          0         1         2         3
0  9.497381  0.552974  0.887313 -1.291874
1  6.461631 -6.206155  9.979247 -0.044828
2  4.276156  2.002518  8.848432 -5.240563
3  1.710331  1.463783  7.535078 -1.399565

df.apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

          0         1         2         3
0  0.515087  0.133967 -0.651699  0.135175
1  0.125241 -0.689446  0.348301  0.375188
2 -0.155414  0.310554  0.223925 -0.624812
3 -0.484913  0.244924  0.079473  0.114448

また、groupby関連する列を選択すると、でうまく機能します。

df['grp'] = ['A', 'A', 'B', 'B']

          0         1         2         3 grp
0  9.497381  0.552974  0.887313 -1.291874   A
1  6.461631 -6.206155  9.979247 -0.044828   A
2  4.276156  2.002518  8.848432 -5.240563   B
3  1.710331  1.463783  7.535078 -1.399565   B


df.groupby(['grp'])[[0,1,2,3]].apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

     0    1    2    3
0  0.5  0.5 -0.5 -0.5
1 -0.5 -0.5  0.5  0.5
2  0.5  0.5  0.5 -0.5
3 -0.5 -0.5 -0.5  0.5

2

少し変更:Python Pandas Dataframe:0.01〜0.99のデータを正規化しますか?しかし、いくつかのコメントから、それは関連性があると考えました(ただし、再投稿と見なされた場合は申し訳ありません...)

データムまたはZスコアの正規パーセンタイルが適切ではないため、カスタマイズした正規化が必要でした。時々、母集団の実行可能な最大値と最小値が何であるかを知っていたため、サンプルや別の中間点など、それ以外のものを定義する必要がありました。これは多くの場合、0と1の間のすべての入力が必要なニューラルネットのデータの再スケーリングと正規化に役立ちますが、パーセンタイルとstdevsはサンプルカバーを想定しているため、一部のデータはよりカスタマイズされた方法でスケーリングする必要がある場合があります。人口ですが、これが真実ではないことを知っている場合もあります。また、ヒートマップでデータを視覚化するときにも非常に役立ちました。だから私はカスタム関数をビルドしました(可能な限り読みやすくするためにここのコードで追加の手順を使用しました):

def NormData(s,low='min',center='mid',hi='max',insideout=False,shrinkfactor=0.):    
    if low=='min':
        low=min(s)
    elif low=='abs':
        low=max(abs(min(s)),abs(max(s)))*-1.#sign(min(s))
    if hi=='max':
        hi=max(s)
    elif hi=='abs':
        hi=max(abs(min(s)),abs(max(s)))*1.#sign(max(s))

    if center=='mid':
        center=(max(s)+min(s))/2
    elif center=='avg':
        center=mean(s)
    elif center=='median':
        center=median(s)

    s2=[x-center for x in s]
    hi=hi-center
    low=low-center
    center=0.

    r=[]

    for x in s2:
        if x<low:
            r.append(0.)
        elif x>hi:
            r.append(1.)
        else:
            if x>=center:
                r.append((x-center)/(hi-center)*0.5+0.5)
            else:
                r.append((x-low)/(center-low)*0.5+0.)

    if insideout==True:
        ir=[(1.-abs(z-0.5)*2.) for z in r]
        r=ir

    rr =[x-(x-0.5)*shrinkfactor for x in r]    
    return rr

これは、pandasシリーズ、または単なるリストを取り込んで、指定された低点、中央点、および高点に正規化します。シュリンクファクターもあります!エンドポイント0と1から離れてデータを縮小できるようにするため(matplotlibでカラーマップを組み合わせるときにこれを行う必要がありました:Matplotlibを使用して複数のカラーマップと単一のpcolormesh)コードがどのように機能するかを確認できますが、基本的にはサンプルには[-5,1,10]の値がありますが、-7から7の範囲に基づいて正規化する必要があります(したがって、7を超えるものはすべて、実質的に2の中点で「10」は7として扱われます)。ただし、256 RGBカラーマップに合わせて縮小します。

#In[1]
NormData([-5,2,10],low=-7,center=1,hi=7,shrinkfactor=2./256)
#Out[1]
[0.1279296875, 0.5826822916666667, 0.99609375]

データを裏返すこともできます...これは奇妙に思えるかもしれませんが、ヒートマッピングに役立つことがわかりました。hi / lowではなく、0に近い値の暗い色が必要だとします。insideout = Trueの正規化データに基づいてヒートマップを作成できます。

#In[2]
NormData([-5,2,10],low=-7,center=1,hi=7,insideout=True,shrinkfactor=2./256)
#Out[2]
[0.251953125, 0.8307291666666666, 0.00390625]

したがって、中心に最も近い「2」が「1」として定義され、これが最も高い値になります。

とにかく、有用なアプリケーションが存在する可能性がある他の方法でデータを再スケーリングする場合は、私のアプリケーションが適切であると思いました。


すべてのif / elseステートメントを、functionsを含む辞書に置き換えることができます。少しきれいに見えます。
Roald

それはかなりきちんとしている、私は次回にそれを覚えておきます、ありがとう!
Vlox、2017年

0

これは、列ごとに行う方法です。

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