sklearn으로 확장 가능한 팬더 데이터 프레임 열


137

혼합 유형 열이있는 팬더 데이터 프레임이 있으며 일부 열에 sklearn의 min_max_scaler를 적용하고 싶습니다. 이상적으로는 이러한 변형을 제자리에서 수행하고 싶지만 아직 그렇게 할 방법을 찾지 못했습니다. 작동하는 다음 코드를 작성했습니다.

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

이것이 이것이이 변환을 수행하는 가장 바람직하고 효율적인 방법인지 궁금합니다. 더 나은 df.apply를 사용할 수있는 방법이 있습니까?

또한 다음 코드를 작동시킬 수 없다는 것에 놀랐습니다.

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

전체 데이터 프레임을 스케일러에 전달하면 작동합니다.

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

스케일러에 시리즈를 전달하지 못하는 이유가 혼란 스럽습니다. 위의 전체 작업 코드에서 시리즈를 스케일러로 전달하고 데이터 프레임 열 =을 스케일링 된 시리즈로 설정하려고했습니다. 나는이 질문이 다른 곳에서 묻는 것을 보았지만 좋은 대답을 찾지 못했습니다. 여기에서 무슨 일이 일어나고 있는지 이해하는 데 도움이 될 것입니다!


1
이 작업을 수행하면 작동합니까 bad_output = min_max_scaler.fit_transform(dfTest['A'].values)? values속성에 액세스하면 numpy 배열이 반환됩니다. 어떤 이유로 때로는 scikit learn api가 팬더가 numpy 배열을 반환하도록하는 올바른 메소드를 올바르게 호출하지만 때로는 그렇지 않습니다.
EdChum

팬더의 데이터 프레임은 scikit-learn의 규칙과 일치하지 않는 규칙을 가진 매우 복잡한 객체입니다. 모든 것을 NumPy 배열로 변환하면 scikit-learn을 사용하는 것이 훨씬 쉬워집니다.
Fred Foo

@edChum- bad_output = in_max_scaler.fit_transform(dfTest['A'].values)작동하지 않았습니다. @larsmans-그래, 나는이 길을 내려가는 것에 대해 생각했다. 팬더가 전체 데이터 프레임을 sklearn 함수에 전달할 수는 있지만 버그는 아닌지 모르겠습니다. 데이터 프레임에 대한 나의 이해는 그것이 일련의 기사라는 것입니다. "Python for Data Analysis"책을 읽으면 NumPy 중심 응용 프로그램에서 쉽게 사용할 수 있도록 팬더가 numpy 위에 빌드되어 있다고합니다.
flyingmeatball

답변:


214

이전 버전 pandas이 이것을 막았 는지 확실하지 않지만 이제 다음 스 니펫이 완벽하게 작동하고 사용하지 않고도 원하는 것을 정확하게 생성합니다.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

80
산뜻한! 보다 일반화 된 버전df[df.columns] = scaler.fit_transform(df[df.columns])
citynorman

6
@RajeshThevar 바깥 쪽 괄호는 팬더가 데이터 프레임에서 열을 선택하도록 지시하는 팬더의 일반적인 선택기 괄호입니다. 내부 괄호는 목록을 나타냅니다. 팬더 선택기에 목록을 전달합니다. 하나의 괄호를 사용하고 하나의 열 이름과 다른 열 이름을 쉼표로 구분하면 pandas는이를 다중 수준 열 (MultiIndex)이있는 데이터 프레임에서 열을 선택하려고하는 것처럼 해석하고 키 오류를 발생시킵니다 .
ken

1
pandas 가이 색인 논리를 구현하는 방법과 값과 튜플이 목록과 다르게 해석되는 이유를 정확하게 보려면 @ken의 대답에 추가하려면 DataFrames가 __getitem__메소드를 구현하는 방법을 볼 수 있습니다 . 특히 당신은 당신에게 ipython을 열고 할 수 있습니다 pd.DataFrame.__getitem__??; 물론 팬더를 pd로 가져온 후;)
LetsPlayYahtzee

4
실용적인 참고 사항 : 기차 / 테스트 데이터 분할을 사용하는 사용자는 테스트 데이터가 아닌 교육 데이터에만 적합해야합니다.
David J.

1
타임 스탬프 열을 제외한 모든 것을 확장하려면 columns =df.columns.drop('timestamps') df[df.columns] = scaler.fit_transform(df[df.columns]
intotecho

19

이렇게요?

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
이 스크립트를 실행할 때 DeprecationWarnings가 많이 있습니다. 어떻게 업데이트해야합니까?
pir

아래 @LetsPlayYahtzee의 답변을 참조하십시오
AJP

2
더 간단한 버전 : dfTest [[ 'A', 'B']] = dfTest [[ 'A', 'B']]. apply (MinMaxScaler (). fit_transform)
Alexandre V.

12

pir의 의견에서 언급 했듯이이 .apply(lambda el: scale.fit_transform(el))방법은 다음 경고를 생성합니다.

DeprecationWarning : 0.17에서 데이터가 더 이상 사용되지 않으므로 1d 배열을 전달하면 0.19에서 ValueError가 발생합니다. 데이터에 단일 기능이있는 경우 X.reshape (-1, 1)을 사용하거나 단일 샘플이 포함 된 경우 X.reshape (1, -1)을 사용하여 데이터를 재구성하십시오.

열을 numpy 배열로 변환하면 작업을 수행해야합니다 (StandardScaler를 선호합니다).

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()

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

- 편집 년 11 월 2018 (팬더에 대한 테스트 0.23.4 ) -

Rob Murray가 주석에서 언급했듯이 현재 (v0.23.4) 버전의 pandas .as_matrix()는을 반환합니다 FutureWarning. 따라서 다음과 같이 바꿔야합니다 .values.

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

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

- 편집 2019년 5월은 (팬더에 대한 테스트 0.24.2 ) -

joelostblom이 주석에서 언급했듯이 " . 대신에 0.24.0사용 .to_numpy()하는 것이 좋습니다 .values."

업데이트 된 예 :

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
사용 .values대신 .as_matrix()으로 as_matrix()지금 수 있습니다 FutureWarning.
Rob Murray


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

감가 상각 경고없이 작동해야합니다.


7

다음을 사용해서 pandas만 할 수 있습니다 .

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
나는 팬더로만 할 수 있다는 것을 알고 있지만 결국 스스로 작성하기 쉽지 않은 다른 sklearn 방법을 적용하고 싶을 수도 있습니다. 더 간단한 솔루션을 만드는 것보다 시리즈에 적용하는 것이 예상대로 작동하지 않는 이유를 알아내는 데 더 관심이 있습니다. 다음 단계는 RandomForestRegressor를 실행하는 것이며 Pandas와 sklearn이 함께 작동하는 방식을 이해하고 싶습니다.
flyingmeatball

5
이 답변은df.max() - df.min() 0 일 수 있으므로 위험 하므로 예외가 발생합니다. 또한 df.min()두 번 계산되어 비효율적입니다. 이 ( df.ptp()는)와 동일합니다 df.max() - df.min().
Acumenus

3

나는 그것이 매우 오래된 의견이라는 것을 알고 있지만 여전히 :

단일 괄호 (dfTest['A'])를 사용 하는 대신 이중 괄호를 사용하십시오 (dfTest[['A']]).

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

나는 이것이 원하는 결과를 줄 것이라고 믿습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.