Pandas 데이터 프레임의 열 정규화


260

각 열의 값 범위가 다른 팬더에 데이터 프레임이 있습니다. 예를 들면 :

df :

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

각 값이 0과 1 사이 인이 데이터 프레임의 열을 어떻게 정규화 할 수 있는지 아십니까?

내 원하는 출력은 다음과 같습니다.

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
기능을 적용가 예 frame.apply (F, 축 = 1) F는 연속으로 무언가를 함수 ...이다
tschm

1
scikit-learn 문서 는 정규화 를 " 단위 표준을 갖도록 개별 샘플을 스케일링 하는 프로세스"로 정의하기 때문에 정규화가 가장 적절한 표현이 아닐 수 있습니다 (예 : 올바르게 이해하면 행 단위로 ).
Skippy le Grand Gourou

이해가 안되는데 왜 min_max 스케일링이 정규화로 간주되는지! 정상은 평균 0과 분산 1을 갖는 정규 분포의 의미를 가져야합니다.
OverFlow Police

2
2020 년 이후에이 질문을 방문하는 경우 @Poudel의 답변을 살펴보면 pandas와 sklearn을 사용하면 정규화에 대한 다른 답변을 얻을 수 있습니다.
Bhishan Poudel

@Poudel은 ddof논쟁 때문입니까?
fffrost

답변:


256

sklearn 패키지 및 관련 전처리 유틸리티를 사용하여 데이터를 정규화 할 수 있습니다.

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)

자세한 내용은 데이터 전처리 : 기능을 범위로 확장 하는 방법에 대한 scikit-learn 문서 를 참조하세요 .


50
나는 이것이 열 이름을 제거 할 것이라고 생각하는데, 이것은 op가 처음에 데이터 프레임을 사용하는 이유 중 하나 일 수 있습니다.
pietz

51
먼저 전치하지 않는 한 열이 아닌 행을 정규화합니다. Q가 요구하는 작업을 수행하려면 :pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)
hobs

30
열 이름을 유지하려면 @pietz 이 게시물을 참조하십시오 . 기본적으로 마지막 줄을 교체df=pandas.DataFrame(x_scaled, columns=df.columns)
ijoseph

5
@hobs 이것은 올바르지 않습니다. Sandman의 코드는 열 단위 및 열 단위로 정규화합니다. 조옮김하면 잘못된 결과를 얻습니다.
petezurich

8
@petezurich Sandman 또는 Praveen이 코드를 수정 한 것 같습니다. 불행히도 댓글을 수정할 수 없습니다.;)
hobs

463

Pandas 를 사용하는 쉬운 방법 : (여기서는 평균 정규화를 사용하고 싶습니다)

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

최소-최대 정규화를 사용하려면 :

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

편집 : 일부 문제를 해결하려면 Pandas가 위 코드에서 자동으로 colomn-wise 함수를 적용한다고 말할 필요가 있습니다.


23
난이게 좋아. 짧고 표현력이 뛰어나며 헤더 정보를 보존합니다. 하지만 분모의 분도 빼야한다고 생각합니다.
pietz

이 솔루션은 아름답고 간결하며 잘못되었습니다. mean () 및 str () 메서드는 데이터 프레임이 아니라 시리즈를 반환합니다. 이는 어리석은 오류 메시지를 생성합니다 ( "ValueError : cannot reindex from a duplicate axis") 작동하는 것을 얻으려면 다음과 같은 방법으로 uglify해야합니다. normalized_df = (df-df.mean (). to_frame (). T) /df.std().to_frame().T
MightyCurious

6
나는 그것이 틀렸다고 생각하지 않는다. 나를 위해 아름답게 작동합니다. mean () 및 std ()가 작동하기 위해 데이터 프레임을 반환해야한다고 생각하지 않으며 오류 메시지가 데이터 프레임이 아니라는 것을 의미하지는 않습니다.
Strandtasche

7
또한 나를 위해 아름답게 일했습니다. @Nguaial 당신은 numpy 행렬에서 이것을 시도 할 수 있습니다.이 경우 결과는 당신이 말한 것입니다. 그러나 Pandas 데이터 프레임의 경우 최소, 최대, ... 측정 값은 기본적으로 열 단위로 적용됩니다.
Auxiliary

어떻게 든 창 기능으로 할 수 있습니까? 내가 의미하는 바는 최근 10 개의 관찰을 기반으로 max () 및 min ()을 계산하는 것입니다.
krakowi

56

이 게시물을 기반으로 : /stats/70801/how-to-normalize-data-to-0-1-range

다음을 수행 할 수 있습니다.

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

당신의 가치가 부정적인지 긍정적인지에 대해 걱정할 필요가 없습니다. 그리고 값은 0과 1 사이에 잘 ​​분산되어야합니다.


9
최소값과 최대 값이 같고 분모가 0이며 NaN 값을 얻을 때주의하십시오.
Hrushikesh Dhumal

@HrushikeshDhumal, 모든 값이 같기 때문에 정규화 할 필요가 없습니다.
Appaji Chintimi

@AppajiChintimi,이 솔루션은 전체 데이터에 적용되며 온 전성 검사를 수행하지 않으면 문제가 발생할 수 있습니다.
Hrushikesh Dhumal

40

문제는 실제로 열에 작용하는 간단한 변환입니다.

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

frame.apply(f, axis=0)

또는 더 간결하게 :

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

3
lambda하나 :-) 최고입니다
아부 Shoeb

4
질문이 열 현명한 정규화이기 때문에 이것이 axis = 1이어야하지 않습니까?
Nguai al

2
아니요, 문서에서 : axis [...] 0 or 'index': apply function to each column. 기본값은 실제로이 axis=0한 줄짜리를 더 짧게 작성할 수 있습니다. :-) 감사합니다 @tschm.
jorijnsmit

35

sklearn 패키지 사용을 좋아한다면 다음과 같이 pandas를 사용하여 열 및 인덱스 이름을 유지할 수 있습니다 loc.

from sklearn.preprocessing import MinMaxScaler

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

29

단순함은 아름답습니다 :

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

6
OP는 [0..1] 범위를 요청했으며이 솔루션은 [-1..1] 범위로 확장됩니다. 배열 [-10, 10]을 사용해보십시오.
Alexander Sosnovshchenko

3
@AlexanderSosnovshchenko 정말 아닙니다. Basil Musa는 OP의 행렬이 항상 음수가 아니라고 가정하고 있으며, 이것이 그가이 솔루션을 제공 한 이유입니다. 일부 열에 음수 항목이 있으면이 코드는 [-1,1] 범위로 정규화되지 않습니다. 배열 [-5, 10]을 사용해보십시오. 음수 값을 사용하여 [0,1]로 정규화하는 올바른 방법은 Cina의 답변에 의해 제공되었습니다df["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())
facuq

간단하고 명시 적
joshi123

더 간단 df /= df.max()할 수도 있습니다 .-목표가 모든 열을 개별적으로 정규화하는 것이라고 가정합니다.
n1k31t4

28

정규화하려는 열 목록을 만들 수 있습니다.

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

Pandas Dataframe은 이제 원하는 열에서만 정규화됩니다.


그러나 반대로 원하는 경우 정규화 하지 않으려 는 열 목록을 선택하고 모든 열 목록을 만들고 원하지 않는 열을 제거하면됩니다.

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 ]

19

파이썬에서 다른 표준화의 예.

참고로이 위키피디아 기사 : 표준 편차의 편향되지 않은 추정

예제 데이터

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

팬더를 사용한 정규화 (편향되지 않은 추정값 제공)

정규화 할 때 단순히 평균을 빼고 표준 편차로 나눕니다.

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

sklearn을 사용한 정규화 (Pandas와는 다른 편향된 추정값 제공)

동일한 작업을 수행하면 sklearn다른 출력을 얻을 수 있습니다!

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

sklearn의 편향된 추정이 기계 학습을 덜 강력하게 만들까요?

아니.

sklearn.preprocessing.scale 의 공식 문서에는 편향 추정기를 사용하는 것이 기계 학습 알고리즘의 성능에 영향을 미칠 가능성없으며 안전하게 사용할 수 있다고 명시되어 있습니다.

공식 문서에서 :

표준 편차에 대해 편향된 추정량을 사용합니다 numpy.std(x, ddof=0). 의 선택은 ddof모델 성능에 영향을주지 않습니다.

MinMax Scaling은 어떻습니까?

MinMax 스케일링에는 표준 편차 계산이 없습니다. 따라서 결과는 pandas와 scikit-learn에서 동일합니다.

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

12

판다에서 더 좋은 방법은

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

편집 데이터 프레임에 음수가 있으면 대신 사용해야합니다.

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

1
열의 모든 값이 0 인 경우 작동하지 않습니다
ahajib

현재 값을 최대 값으로 나누면 최소값이 0이 아니면 올바른 정규화가 제공되지 않습니다.
pietz

동의합니다. 그러나 구약이 요청한 것입니다 (그의 예 참조)
Daniele

11

Sandman과 Praveen이 제공 한 솔루션은 매우 훌륭합니다. 데이터 프레임의 다른 열에 범주 형 변수가있는 경우이 방법은 약간의 조정이 필요합니다.

이 유형의 문제에 대한 나의 해결책은 다음과 같습니다.

 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
이 대답은 인터넷의 대부분의 예제가 모든 열에 하나의 스케일러를 적용하는 반면, 실제로는 하나의 스케일러 (예 : MinMaxScaler)가 모든 열에 적용되지 않아야하는 상황을 해결하기 때문에 유용합니다.
demongolem

7

일부 열은 정규화되고 다른 열은 데이터 레이블 또는 범주 열이 변경되지 않은 일부 회귀 작업처럼 변경되지 않을 수 있으므로이 비단뱀적인 방법을 제안합니다 (@shg 및 @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()))

6

단순한 수학 일뿐입니다. 대답은 아래와 같이 간단해야합니다.

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

3

다음은 목록 이해를 사용하여 열 방식으로 수행하는 방법입니다.

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


2
def normalize(x):
    try:
        x = x/np.linalg.norm(x,ord=1)
        return x
    except :
        raise
data = pd.DataFrame.apply(data,normalize)

Pandas의 문서에서 DataFrame 구조는 작업 (함수)을 자체에 적용 할 수 있습니다.

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

DataFrame의 입력 축을 따라 기능을 적용합니다. 함수에 전달 된 객체는 DataFrame의 인덱스 (axis = 0) 또는 열 (axis = 1) 중 하나에 인덱스가있는 Series 객체입니다. 반환 유형은 전달 된 함수 집계 여부 또는 DataFrame이 비어있는 경우 reduce 인수에 따라 다릅니다.

사용자 정의 함수를 적용하여 DataFrame을 작동 할 수 있습니다.


3
코드가 OP 문제를 해결하는 이유를 설명하면 사람들이 단순히 코드를 복사하는 대신 전략을 조정할 수 있습니다. 좋은 답변을 어떻게 작성합니까?를
미스터 T

2

다음 함수는 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

1

다음과 같이 간단하게 pandas.DataFrame.transform 1 함수를 사용할 수 있습니다 .

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

이 솔루션은 모든 값이 음수이면 작동하지 않습니다. [-1, -2, -3]을 고려하십시오. -1로 나누면 [1,2,3]이됩니다.
Dave Liu

0

한 줄로 할 수 있습니다.

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

각 열에 대한 평균을 취한 다음 모든 행에서 (평균)을 빼고 (특정 열의 평균은 해당 행에서만 빼기) 평균으로 만 나눕니다. 마지막으로, 우리가 얻는 것은 정규화 된 데이터 세트입니다.


0

Pandas는 기본적으로 열 단위 정규화를 수행합니다. 아래 코드를 시도하십시오.

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

출력 값의 범위는 0과 1입니다.


0

데이터가 양으로 치우친 경우 정규화하는 가장 좋은 방법은 로그 변환을 사용하는 것입니다.

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