2014-07-09 35 views
38

Mam pandasową ramkę danych z kolumnami typu mieszanego, a do niektórych kolumn chciałabym zastosować minilax_scaler firmy sklearn. Idealnie, chciałbym wprowadzić te transformacje w miejscu, ale nie znalazłem jeszcze sposobu, aby to zrobić. Napisałem następujący kod, który działa:panda kolumny ramek danych skalowanie ze sklearn

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 istnieje sposób mogę użyć df.apply, że byłoby lepiej?

Jestem również zaskoczony, nie mogę się następujący kod do pracy:

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

Gdybym przejść całą dataframe do skalera to działa:

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

Jestem zdezorientowany, dlaczego przejście serii do skalera kończy się niepowodzeniem. W moim pełnym roboczym kodzie powyżej miałem nadzieję, że po prostu przekażę serię do skalera, a następnie ustawię kolumnę typu danych = w skalowanej serii. Widziałem, jak to pytanie zadawało kilka innych miejsc, ale nie znalazłem dobrej odpowiedzi. Każda pomoc w zrozumieniu tego, co się tutaj dzieje, byłaby ogromnie doceniona!

+1

to działa, jeśli nie to 'bad_output = min_max_scaler.fit_transform (dfTest [ 'a'] wartości.) '? uzyskanie dostępu do atrybutu "values" zwraca tablicę numpy, z jakiegoś powodu czasami api do nauki scikit poprawnie wywoła właściwą metodę, która sprawia, że ​​pandy zwracają tablicę numpy, a czasem nie. – EdChum

+0

Frameworki Pand to dość skomplikowane obiekty z konwencjami, które nie pasują do konwencji science-fiction. Jeśli skonwertujesz wszystko na tablice NumPy, scikit-learn stanie się o wiele łatwiejszy w obsłudze. –

+0

@edChum - 'bad_output = in_max_scaler.fit_transform (dfTest ['A'] wartości)' nie działa. @larsmans - tak, myślałam o pójściu tą trasą, to po prostu wygląda na kłopot. Nie wiem, czy to błąd, czy nie, że Pandy mogą przekazać pełną ramkę danych do funkcji sklearn, ale nie serii. Moje zrozumienie ramy danych polegało na tym, że jest to dyktat serii.W książce "Python for Data Analysis" czytamy, że panda jest zbudowana na zasadzie numpy, aby ułatwić jej stosowanie w aplikacjach NumPy-centric. – flyingmeatball

Odpowiedz

44

Nie jestem pewien, czy wcześniejsze wersje pandas uniknąć tego, ale teraz następujący fragment działa idealnie dla mnie i daje dokładnie to, co chcesz, bez konieczności korzystania z apply

>>> 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 
+3

Schludny! Bardziej ogólna wersja 'df [df.columns] = scaler.fit_transform (df [df.columns])' – citynorman

+0

Wiem, że jest to opóźniony komentarz od oryginalnej daty, ale dlaczego są dwa nawiasy kwadratowe w dfTest [['A' , 'B']]? Widzę, że nie działa z pojedynczym nawiasem, ale nie mógł zrozumieć przyczyny. –

+2

@RajeshThevar Zewnętrzne nawiasy są typowymi paskami selektora pandy, mówiąc pandom, aby wybrały kolumnę z ramki danych. Wewnętrzne nawiasy wskazują listę. Przepisujesz listę do selektora pand. Jeśli użyjesz pojedynczych nawiasów - z jedną kolumną, po której następna, oddzielone przecinkami - interpretuje to tak, jakbyś próbował wybrać kolumnę z ramek danych z wielopoziomowymi kolumnami (MultiIndex) i rzuci keykeor . – ken

3

Można to zrobić za pomocą 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 
+3

Wiem, że mogę to zrobić tylko w pandach, ale mogę ewentualnie zastosować inną metodę sklearn, która nie jest tak łatwa do napisania. Bardziej interesuje mnie zastanawianie się, dlaczego zastosowanie do serii nie działa tak, jak się spodziewałem, niż gdybym wymyślił prostsze rozwiązanie. Następnym krokiem będzie uruchomienie RandomForestRegressor i chcę się upewnić, że rozumiem, jak Pandas i sklearn współpracują ze sobą. – flyingmeatball

16

takiego?

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

Po uruchomieniu tego skryptu otrzymuję pakiet DeprecationWarnings. Jak powinien zostać zaktualizowany? – pir

+0

Poniższa odpowiedź działa bez ostrzeżenia – wi3o

+0

Zobacz odpowiedź @LetsPlayYahtzee poniżej – AJP

4

Jak to jest wymienione w komentarzu pir - metoda .apply(lambda el: scale.fit_transform(el)) wygeneruje następujące ostrzeżenie:

Przestarzałe Ostrzeżenie: przekazywanie tablic 1d, ponieważ dane są uznawane za przestarzałe w 0.17 i podniesie ValueError w 0.19. Zmień swoje dane za pomocą X.reshape (-1, 1), jeśli dane mają jedną funkcję lub X.reshape (1, -1) , jeśli zawiera pojedynczą próbkę.

Konwersja kolumn do NumPy tablic należy wykonać zadanie (wolę StandardScaler):

from sklearn.preprocessing import StandardScaler 
scale = StandardScaler() 

dfTest[['A','B','C']] = scale.fit_transform(dfTest[['A','B','C']].as_matrix()) 
Powiązane problemy