sklearn ile ölçeklenen pandalar veri çerçevesi sütunları


138

Karışık tip sütunlara sahip bir panda veri çerçevem ​​var ve sklearn'ın min_max_scaler'ını bazı sütunlara uygulamak istiyorum. İdeal olarak, bu dönüşümleri yerinde yapmak isterdim, ancak bunu yapmanın bir yolunu henüz bulamadım. Çalışan şu kodu yazdım:

import pandas as pd
import numpy as np
from sklearn import preprocessing

scaler = preprocessing.MinMaxScaler()

dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
min_max_scaler = preprocessing.MinMaxScaler()

def scaleColumns(df, cols_to_scale):
    for col in cols_to_scale:
        df[col] = pd.DataFrame(min_max_scaler.fit_transform(pd.DataFrame(dfTest[col])),columns=[col])
    return df

dfTest

    A   B   C
0    14.00   103.02  big
1    90.20   107.26  small
2    90.95   110.35  big
3    96.27   114.23  small
4    91.21   114.68  small

scaled_df = scaleColumns(dfTest,['A','B'])
scaled_df

A   B   C
0    0.000000    0.000000    big
1    0.926219    0.363636    small
2    0.935335    0.628645    big
3    1.000000    0.961407    small
4    0.938495    1.000000    small

Bu dönüşümü yapmanın tercih edilen / en verimli yolu bu mu merak ediyorum. Df.apply'i kullanmanın daha iyi bir yolu var mı?

Çalışmak için aşağıdaki kodu alamadığıma da şaşırdım:

bad_output = min_max_scaler.fit_transform(dfTest['A'])

Ölçekleyiciye bir veri çerçevesinin tamamını iletirsem, çalışır:

dfTest2 = dfTest.drop('C', axis = 1) good_output = min_max_scaler.fit_transform(dfTest2) good_output

Ölçekleyiciye bir dizi geçirmenin neden başarısız olduğu kafam karıştı. Yukarıdaki tam çalışma kodumda, ölçekleyiciye bir dizi geçirmeyi ve ardından veri çerçevesi sütununu = ölçeklenmiş seriye ayarlamayı ummuştum. Bu sorunun birkaç yerde daha sorulduğunu gördüm, ancak iyi bir cevap bulamadım. Burada neler olup bittiğini anlamak için herhangi bir yardım çok takdir edilecektir!


1
Bunu yaparsan işe yarıyor mu bad_output = min_max_scaler.fit_transform(dfTest['A'].values)? valuesözniteliğe erişmek bir numpy dizisi döndürür, bazı nedenlerden dolayı bazen scikit learn api pandaların bir numpy dizisi döndürmesini sağlayan doğru yöntemi doğru bir şekilde çağırır ve bazen de döndürmez.
EdChum

Pandaların veri çerçeveleri, scikit-learn kurallarına uymayan kurallara sahip oldukça karmaşık nesnelerdir. Her şeyi NumPy dizilerine dönüştürürseniz, scikit-learn ile çalışmak çok daha kolay hale gelir.
Fred Foo

@edChum - bad_output = in_max_scaler.fit_transform(dfTest['A'].values)da işe yaramadı. @larsmans - evet bu yoldan gitmeyi düşünmüştüm, sadece bir güçlük gibi görünüyor. Pandaların tam bir veri çerçevesini bir sklearn fonksiyonuna geçirebilmesi, ancak bir seriye geçememesi bir hata olup olmadığını bilmiyorum. Bir veri çerçevesine ilişkin anlayışım, bunun bir dizi diktesi olduğuydu. "Veri Analizi için Python" kitabında okunduğunda, pandaların NumPy merkezli uygulamalarda kullanımını kolaylaştırmak için numpy üzerine inşa edildiğini belirtir.
flyingmeatball

Yanıtlar:


215

Önceki sürümlerin pandasbunu engellediğinden emin değilim, ancak şimdi aşağıdaki kod parçası benim için mükemmel çalışıyor ve kullanmak zorunda kalmadan tam olarak istediğiniz şeyi üretiyorapply

>>> import pandas as pd
>>> from sklearn.preprocessing import MinMaxScaler


>>> scaler = MinMaxScaler()

>>> dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],
                           'B':[103.02,107.26,110.35,114.23,114.68],
                           'C':['big','small','big','small','small']})

>>> dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A', 'B']])

>>> dfTest
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

80
Temiz! Daha genel bir versiyondf[df.columns] = scaler.fit_transform(df[df.columns])
citynorman

6
@RajeshThevar Dış köşeli parantezler, pandalara veri çerçevesinden bir sütun seçmelerini söyleyen tipik seçici parantezleridir. İç köşeli parantezler bir listeyi belirtir. Pandalar seçiciye bir liste gönderiyorsunuz. Yalnızca tek köşeli parantez kullanırsanız (bir sütun adının ardından diğerinin virgülle ayrılmış olduğu) pandalar bunu, çok düzeyli sütunlara (MultiIndex) sahip bir veri çerçevesinden bir sütun seçmeye çalışıyormuşsunuz gibi yorumlar ve bir anahtar hata atar .
ken

1
Pandaların bu indeksleme mantığını tam olarak nasıl uyguladığını ve neden bir dizi değerin bir listeden farklı yorumlanacağını görmek istiyorsanız @ ken'in cevabına eklemek için DataFrame'in __getitem__yöntemi nasıl uyguladığına bakabilirsiniz . Özellikle ipython'u açıp yapabilirsiniz pd.DataFrame.__getitem__??; pandaları elbette pd olarak içe aktardıktan sonra;)
LetsPlayYahtzee

4
Pratik bir not: Eğitim / test veri bölmelerini kullananlar için, test verilerinize değil, yalnızca egzersiz verilerinize uymak isteyeceksiniz.
David J.

1
Zaman damgaları sütunu dışında tümünü ölçeklemek için,columns =df.columns.drop('timestamps') df[df.columns] = scaler.fit_transform(df[df.columns]
intotecho

19

Bunun gibi?

dfTest = pd.DataFrame({
           'A':[14.00,90.20,90.95,96.27,91.21],
           'B':[103.02,107.26,110.35,114.23,114.68], 
           'C':['big','small','big','small','small']
         })
dfTest[['A','B']] = dfTest[['A','B']].apply(
                           lambda x: MinMaxScaler().fit_transform(x))
dfTest

    A           B           C
0   0.000000    0.000000    big
1   0.926219    0.363636    small
2   0.935335    0.628645    big
3   1.000000    0.961407    small
4   0.938495    1.000000    small

3
Bu betiği çalıştırdığımda bir sürü DeprecationWarnings alıyorum. Nasıl güncellenmelidir?
pir

Aşağıdaki @ LetsPlayYahtzee'nin cevabına bakın
AJP

2
Daha basit bir sürüm: dfTest [['A', 'B']] = dfTest [['A', 'B']]. Uygula (MinMaxScaler (). Fit_transform)
Alexandre V.

12

Pir'in yorumunda bahsedildiği gibi - .apply(lambda el: scale.fit_transform(el))yöntem aşağıdaki uyarıyı verecektir:

Kullanımdan Kaldırma Uyarı: 1d dizileri veri olarak geçirmek 0.17'de kullanımdan kaldırıldı ve 0.19'da ValueError'ı yükseltecek. Verilerinizin tek bir özelliği varsa X.reshape (-1, 1) veya tek bir örnek içeriyorsa X.reshape (1, -1) kullanarak verilerinizi yeniden şekillendirin.

Sütunlarınızı numpy dizilerine dönüştürmek işi yapmalıdır (StandardScaler'ı tercih ederim):

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()

dfTest[['A','B','C']] = scale.fit_transform(dfTest[['A','B','C']].as_matrix())

- Kasım 2018'i Düzenle (Pandalar için test edildi 0.23.4 ) -

Rob Murray'in yorumlarda bahsettiği gibi, pandaların mevcut (v0.23.4) sürümünde .as_matrix()geri dönüyor FutureWarning. Bu nedenle, şu şekilde değiştirilmelidir .values:

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

scaler.fit_transform(dfTest[['A','B']].values)

- Mayıs 2019'u Düzenle (Pandalar için test edildi 0.24.2 ) -

Joelostblom'un yorumlarda belirttiği gibi, "Çünkü bunun yerine 0.24.0kullanılması tavsiye edilir .".to_numpy().values

Güncellenen örnek:

import pandas as pd
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
dfTest = pd.DataFrame({
               'A':[14.00,90.20,90.95,96.27,91.21],
               'B':[103.02,107.26,110.35,114.23,114.68],
               'C':['big','small','big','small','small']
             })
dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A','B']].to_numpy())
dfTest
      A         B      C
0 -1.995290 -1.571117    big
1  0.436356 -0.603995  small
2  0.460289  0.100818    big
3  0.630058  0.985826  small
4  0.468586  1.088469  small

1
kullanmak .valuesyerine .as_matrix()olarak as_matrix()artık verir FutureWarning.
Rob Murray


10
df = pd.DataFrame(scale.fit_transform(df.values), columns=df.columns, index=df.index)

Bu, amortisman uyarıları olmadan çalışmalıdır.


7

Bunu pandasyalnızca kullanarak yapabilirsiniz :

In [235]:
dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
df = dfTest[['A', 'B']]
df_norm = (df - df.min()) / (df.max() - df.min())
print df_norm
print pd.concat((df_norm, dfTest.C),1)

          A         B
0  0.000000  0.000000
1  0.926219  0.363636
2  0.935335  0.628645
3  1.000000  0.961407
4  0.938495  1.000000
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

6
Bunu sadece pandalarda yapabileceğimi biliyorum, ancak sonunda kendim yazmak kadar kolay olmayan farklı bir sklearn yöntemi uygulamak isteyebilirim. Bir seriye başvurmanın neden beklediğimden daha iyi sonuç vermediğini anlamakla daha çok ilgileniyorum. Kesinlikle daha basit bir çözüm bulmak. Bir sonraki adımım bir RandomForestRegressor çalıştırmak olacak ve Pandalar ile sklearn'ın birlikte nasıl çalıştığını anladığımdan emin olmak istiyorum.
flyingmeatball

5
Bu cevap tehlikelidir çünkü df.max() - df.min()0 olabilir ve bir istisnaya neden olabilir. Dahası, df.min()verimsiz olan iki kez hesaplanır. Bunun df.ptp()eşdeğer olduğunu unutmayın df.max() - df.min().
Acumenus

3

Bunun çok eski bir yorum olduğunu biliyorum ama yine de:

Tek köşeli (dfTest['A'])parantez kullanmak yerine çift ​​parantez kullanın (dfTest[['A']]).

yani: min_max_scaler.fit_transform(dfTest[['A']]).

Bunun istenen sonucu vereceğine inanıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.