Mam ramkę danych pandy z kolumnami typu mieszanego i chciałbym zastosować min_max_scaler sklearn do niektórych kolumn. Idealnie, chciałbym dokonać tych transformacji na miejscu, ale jeszcze nie wymyśliłem sposobu, aby to zrobić. Napisałem następujący kod, który działa:
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
Jestem ciekawy, czy jest to preferowany / najbardziej efektywny sposób przeprowadzenia tej transformacji. Czy jest sposób, w jaki mógłbym użyć df.apply, który byłby lepszy?
Dziwię się też, że nie mogę uruchomić następującego kodu:
bad_output = min_max_scaler.fit_transform(dfTest['A'])
Jeśli przekażę całą ramkę danych do skalera, to działa:
dfTest2 = dfTest.drop('C', axis = 1)
good_output = min_max_scaler.fit_transform(dfTest2)
good_output
Nie wiem, dlaczego przekazanie serii do skalera zawodzi. W moim pełnym kodzie roboczym powyżej miałem nadzieję, że przekażę serię do skalera, a następnie ustawię kolumnę dataframe = na skalowaną serię. Widziałem to pytanie zadane w kilku innych miejscach, ale nie znalazłem dobrej odpowiedzi. Każda pomoc w zrozumieniu tego, co się tutaj dzieje, byłaby bardzo mile widziana!
źródło
bad_output = min_max_scaler.fit_transform(dfTest['A'].values)
? dostęp dovalues
atrybutu zwraca tablicę numpy, z jakiegoś powodu czasami scikit learn api poprawnie wywoła właściwą metodę, która sprawia, że pandy zwracają tablicę numpy, a czasami nie.bad_output = in_max_scaler.fit_transform(dfTest['A'].values)
też nie działa. @larsmans - tak, myślałem o zjechaniu tą trasą, wydaje się to po prostu kłopotliwe. Nie wiem, czy jest to błąd, czy nie, że Pandy mogą przekazać pełną ramkę danych do funkcji sklearn, ale nie serię. Moje rozumienie ramki danych było takie, że jest ona dyktatem serii. Czytając książkę „Python for Data Analysis”, stwierdza się, że pandy są zbudowane na bazie numpy, aby ułatwić korzystanie z aplikacji opartych na NumPy.Odpowiedzi:
Nie jestem pewien, czy poprzednie wersje
pandas
temu zapobiegały, ale teraz następujący fragment działa idealnie dla mnie i produkuje dokładnie to, czego chcesz, bez konieczności użyciaapply
>>> 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
źródło
df[df.columns] = scaler.fit_transform(df[df.columns])
__getitem__
metodę. W szczególności możesz otworzyć ipython i zrobićpd.DataFrame.__getitem__??
; po zaimportowaniu pandy jako pd oczywiście;)columns =df.columns.drop('timestamps') df[df.columns] = scaler.fit_transform(df[df.columns]
Lubię to?
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
źródło
Jak wspomniano w komentarzu pir -
.apply(lambda el: scale.fit_transform(el))
metoda zwróci następujące ostrzeżenie:Konwersja kolumn do tablic numpy powinna wystarczyć (wolę StandardScaler):
from sklearn.preprocessing import StandardScaler scale = StandardScaler() dfTest[['A','B','C']] = scale.fit_transform(dfTest[['A','B','C']].as_matrix())
- Edycja listopad 2018 (testowane dla pand 0.23.4 ) -Jak Rob Murray wspomina w komentarzach, w obecnej (v0.23.4) wersji pandy
.as_matrix()
powracaFutureWarning
. Dlatego należy go zastąpić.values
:from sklearn.preprocessing import StandardScaler scaler = StandardScaler() scaler.fit_transform(dfTest[['A','B']].values)
- Edycja maj 2019 (testowane dla pand 0.24.2 ) -
Jak wspomina joelostblom w komentarzach: „Ponieważ
0.24.0
zaleca się używanie.to_numpy()
zamiast.values
”.Zaktualizowany przykład:
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
źródło
.values
zamiast,.as_matrix()
jakas_matrix()
teraz dajeFutureWarning
.0.24.0
, to zaleca się stosowanie.to_numpy()
zamiast.values
.Powinno to działać bez ostrzeżeń o amortyzacji.
źródło
Możesz to zrobić używając
pandas
tylko: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
źródło
df.max() - df.min()
może wynosić 0, co prowadzi do wyjątku. Ponadtodf.min()
jest obliczany dwukrotnie, co jest nieefektywne. Zauważ, żedf.ptp()
jest to równoważne zdf.max() - df.min()
.Wiem, że to bardzo stary komentarz, ale nadal:
Zamiast używać pojedynczego nawiasu
(dfTest['A'])
, użyj podwójnych(dfTest[['A']])
.tj
min_max_scaler.fit_transform(dfTest[['A']])
.Wierzę, że da to pożądany efekt.
źródło
(Testowane dla pand w wersji 1.0.5 )
Na podstawie odpowiedzi @athlonshi (wystąpił błąd ValueError: nie można przekonwertować ciągu na zmiennoprzecinkowy: 'duży' , w kolumnie C), pełny działający przykład bez ostrzeżenia:
import pandas as pd from sklearn.preprocessing import MinMaxScaler scale = preprocessing.MinMaxScaler() df = 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'] }) print(df) df[["A","B"]] = pd.DataFrame(scale.fit_transform(df[["A","B"]].values), columns=["A","B"], index=df.index) print(df) 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 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
źródło