Normalisasi kolom bingkai data panda


227

Saya memiliki dataframe dalam panda di mana setiap kolom memiliki rentang nilai yang berbeda. Sebagai contoh:

df:

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

Adakah yang tahu bagaimana saya bisa menormalkan kolom-bingkai dataframe ini di mana setiap nilai antara 0 dan 1?

Output yang saya inginkan adalah:

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
ada fungsi yang berlaku, misalnya frame.apply (f, axis = 1) di mana f adalah fungsi yang melakukan sesuatu dengan baris ...
tschm

1
Normalisasi mungkin bukan kata yang paling tepat, karena dokumentasi scikit-belajar mendefinisikannya sebagai "proses penskalaan sampel individu untuk memiliki norma satuan " (yaitu baris demi baris, jika saya mendapatkannya dengan benar).
Skippy le Grand Gourou

Saya tidak mengerti, mengapa penskalaan min_max dianggap normalisasi! normal harus memiliki arti dalam arti distribusi normal dengan mean nol dan varian 1.
OverFlow Police

Jika Anda mengunjungi pertanyaan ini pada tahun 2020 atau lebih baru, lihat jawaban oleh @Poudel, Anda mendapatkan jawaban yang berbeda untuk melakukan normalisasi jika Anda menggunakan panda vs sklearn.
Bhishan Poudel

@Poudel apakah ini karena ddofargumennya?
fffrost

Jawaban:


224

Anda dapat menggunakan sklearn paket dan utilitas preprocessing terkait untuk menormalkan data.

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)

Untuk informasi lebih lanjut, lihat dokumentasi scikit-learn pada data preprocessing: penskalaan fitur ke kisaran.


46
Saya pikir ini akan menghilangkan nama kolom, yang mungkin menjadi salah satu alasan op menggunakan dataframe di tempat pertama.
pietz

47
Ini akan menormalkan baris dan bukan kolom, kecuali jika Anda memindahkannya terlebih dahulu. Untuk melakukan apa yang diminta oleh Q:pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)
hobs

26
@pietz untuk menyimpan nama kolom, lihat posting ini . Pada dasarnya ganti baris terakhir dengan,df=pandas.DataFrame(x_scaled, columns=df.columns)
ijoseph

5
@ hobs Ini tidak benar. Kode Sandman menormalkan kolom-bijaksana dan per-kolom. Anda mendapatkan hasil yang salah jika Anda memindahkan.
petezurich

8
@ petezurich Sepertinya Sandman atau Praveen memperbaiki kode mereka. Sayangnya, komentar tidak mungkin;)
hobs

398

satu cara mudah dengan menggunakan Panda : (di sini saya ingin menggunakan normalisasi rata-rata)

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

untuk menggunakan normalisasi min-max:

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

Sunting: Untuk mengatasi beberapa masalah, perlu dikatakan bahwa Panda secara otomatis menerapkan fungsi colomn-wise dalam kode di atas.


16
Saya suka yang ini. singkat, ekspresif, dan menjaga informasi tajuk. tetapi saya pikir Anda perlu mengurangi min di penyebut juga.
pietz

6
Saya tidak berpikir itu salah. Bekerja dengan baik untuk saya - saya tidak berpikir mean () dan std () perlu mengembalikan kerangka data agar ini berfungsi dan pesan kesalahan Anda tidak menyiratkan bahwa mereka tidak menjadi kerangka data adalah masalah.
Strandtasche

24
ini bukan normalisasi bijaksana kolom. ini menormalkan seluruh matriks secara keseluruhan yang akan memberikan hasil yang salah.
Nguai al

6
Juga bekerja untuk saya dengan indah. @ Nguaial Anda mungkin mencoba ini pada matriks numpy dalam hal ini hasilnya adalah apa yang Anda katakan. Tetapi untuk kerangka data Pandas, ukuran min, maks, ... berlaku secara kolom.
Auxiliary

1
Saya suka yang ini juga
Isaac Sim

51

Berdasarkan pos ini: /stats/70801/how-to-normalize-data-to-0-1-range

Anda dapat melakukan hal berikut:

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

Anda tidak perlu khawatir tentang apakah nilai Anda negatif atau positif. Dan nilainya harus tersebar dengan baik antara 0 dan 1.


8
Hati-hati saat nilai min dan maks sama, penyebut Anda 0 dan Anda akan mendapatkan nilai NaN.
Hrushikesh Dhumal

36

Masalah Anda sebenarnya adalah transformasi sederhana yang bekerja pada kolom:

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

frame.apply(f, axis=0)

Atau bahkan lebih singkat:

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

2
Yang lambdasatu adalah yang terbaik :-)
Abu Shoeb 818

4
bukankah ini seharusnya sumbu = 1 karena pertanyaannya adalah normalisasi bijaksana kolom?
Nguai al

Tidak, dari docs : axis [...] 0 or 'index': apply function to each column. Standarnya sebenarnya axis=0jadi one-liner ini bisa ditulis lebih pendek :-) Terima kasih @tschm.
jorijnsmit

30

Jika Anda suka menggunakan paket sklearn, Anda dapat menyimpan kolom dan nama indeks dengan menggunakan panda locseperti:

from sklearn.preprocessing import MinMaxScaler

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

27

Sederhana itu indah:

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

Hebat dan menurut saya solusi terbaik!
Maciej A. Bednarz

6
Perhatikan, OP itu menanyakan kisaran [0..1] dan solusi ini menskala ke kisaran [-1..1]. Coba ini dengan array [-10, 10].
Alexander Sosnovshchenko

3
@AlexanderSosnovshchenko tidak terlalu. Basil Musa mengasumsikan matriks OP selalu non-negatif, karena itu ia memberikan solusi ini. Jika beberapa kolom memiliki entri negatif maka kode ini TIDAK menormalkan ke kisaran [-1,1]. Cobalah dengan array [-5, 10]. Cara yang benar untuk menormalkan ke [0,1] dengan nilai negatif diberikan oleh jawaban Cinadf["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())
facuq

sederhana DAN eksplisit
joshi123

Mungkin lebih sederhana: df /= df.max()- dengan asumsi tujuannya adalah untuk menormalkan setiap kolom, secara individual.
n1k31t4

24

Anda dapat membuat daftar kolom yang ingin dinormalisasi

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

Bingkai Data Pandas Anda sekarang dinormalisasi hanya pada kolom yang Anda inginkan


Namun , jika Anda menginginkan yang sebaliknya , pilih daftar kolom yang TIDAK ingin Anda normalkan, Anda bisa membuat daftar semua kolom dan menghapus yang tidak diinginkan

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

Saya pikir cara yang lebih baik untuk melakukannya dalam panda adalah adil

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

Sunting Jika dalam bingkai data Anda ada angka negatif yang harus Anda gunakan sebagai gantinya

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

1
Jika semua nilai kolom adalah nol, ini tidak akan berfungsi
ahajib

membagi nilai saat ini dengan maks tidak akan memberi Anda normalisasi yang benar kecuali min adalah 0.
pietz

Saya setuju, tetapi itulah yang diminta oleh PL (lihat contohnya)
Daniele

11

Solusi yang diberikan oleh Sandman dan Praveen sangat baik. Satu-satunya masalah dengan itu jika Anda memiliki variabel kategori di kolom lain dari bingkai data Anda metode ini akan membutuhkan beberapa penyesuaian.

Solusi saya untuk jenis masalah ini adalah sebagai berikut:

 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
Jawaban ini bermanfaat karena sebagian besar contoh di internet menerapkan satu scaler ke semua kolom, sedangkan ini sebenarnya membahas situasi di mana satu scaler, misalnya MinMaxScaler, seharusnya tidak berlaku untuk semua kolom.
demongolem

10

Contoh standardisasi berbeda dalam python.

Untuk referensi lihat artikel wikipedia ini: https://en.wikipedia.org/wiki/Unprice_estimation_of_standard_deviation

Contoh Data

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

Normalisasi menggunakan panda (Memberikan perkiraan tidak bias)

Ketika menormalkan kita cukup mengurangi mean dan membaginya dengan standar deviasi.

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

Normalisasi menggunakan sklearn (Memberikan perkiraan bias, berbeda dari panda)

Jika Anda melakukan hal yang sama dengan sklearnAnda akan mendapatkan hasil yang BERBEDA!

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

Apakah perkiraan bias sklearn membuat Pembelajaran Mesin Kurang Kuat?

TIDAK.

Dokumentasi resmi sklearn.preprocessing.scale menyatakan bahwa menggunakan estimator yang bias TIDAK UNIK untuk mempengaruhi kinerja algoritma pembelajaran mesin dan kita dapat menggunakannya dengan aman.

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.

Bagaimana dengan Scaling MinMax?

Tidak ada perhitungan Standar Deviasi dalam penskalaan MinMax. Jadi hasilnya sama di kedua panda dan scikit-belajar.

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

Anda mungkin ingin memiliki beberapa kolom yang dinormalisasi dan yang lainnya tidak berubah seperti beberapa tugas regresi yang label data atau kolom kategorinya tidak berubah. Jadi saya sarankan Anda cara pythonic ini (Ini kombinasi dari jawaban @shg dan @Cina):

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

Ini hanya matematika sederhana. Jawabannya harus sesederhana seperti di bawah ini.

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)

Dari dokumen panda, struktur DataFrame dapat menerapkan operasi (fungsi) untuk dirinya sendiri.

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

Menerapkan fungsi di sepanjang sumbu input DataFrame. Objek yang diteruskan ke fungsi adalah objek Seri yang memiliki indeks, baik indeks DataFrame (sumbu = 0) atau kolom (sumbu = 1). Jenis pengembalian tergantung pada apakah fungsi yang disahkan agregat, atau argumen pengurangan jika DataFrame kosong.

Anda dapat menerapkan fungsi khusus untuk mengoperasikan DataFrame.


2
Akan lebih baik untuk menjelaskan, mengapa kode Anda memecahkan masalah OP, sehingga orang dapat menyesuaikan strategi daripada hanya menyalin kode Anda. Silakan baca Bagaimana saya menulis jawaban yang bagus?
Tn.

2

Fungsi berikut menghitung skor 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

Ini adalah bagaimana Anda melakukannya dengan bijaksana menggunakan pemahaman daftar:

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

1

Anda cukup menggunakan fungsi pandas.DataFrame.transform 1 dengan cara ini:

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

Solusi ini tidak akan berfungsi jika semua nilai negatif. Pertimbangkan [-1, -2, -3]. Kami membagi dengan -1, dan sekarang kami memiliki [1,2,3].
Dave Liu


0

Anda dapat melakukan ini dalam satu baris

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

dibutuhkan rata-rata untuk setiap kolom dan kemudian kurangi (rata-rata) dari setiap baris (rata-rata kolom tertentu hanya mengurangi dari barisnya saja) dan bagi dengan rata-rata saja. Akhirnya, yang kami dapatkan adalah kumpulan data yang dinormalisasi.


0

Panda melakukan normalisasi bijaksana kolom secara default. Coba kode di bawah ini.

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

Nilai output akan berada dalam kisaran 0 dan 1.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.