Spark & Hadoop/SparkML

[SparkML] Spark ML 피쳐 변환(문자 카테고리형 데이터 처리, Scaling, Null값 채우기) (StringIndexer, OneHotEncoder) (StandardScaler, MinMaxScaler) (Imputer)

YSY^ 2023. 10. 14. 21:20

피쳐 추출과 변환

  • 피쳐 값들을 모델 훈련에 적합한 형태로 바꾸는 것을 지칭
  • 파이썬과 다르게 각각의 feature를 모델에 넣는 것이 아닌 feature를 하나의 vector로 묶어서 모델에 넣음
  • 크게 두 가지가 존재: Feature Extractor와 Feature Transformer
  • Feature Transformer
    • https://spark.apache.org/docs/latest/ml-features.html#feature-transformers
    • 피쳐 값들은 숫자 필드이어야함
      • 텍스트 필드(카테고리 값들)를 숫자 필드로 변환해야함
    • 숫자 필드 값의 범위 표준화
      • 숫자 필드라고 해도 가능한 값의 범위를 특정 범위(0부터 1)로 변환해야 함
      • 이를 피쳐 스케일링 (Feature Scaling) 혹은 정규화 (Normalization)라고 지칭
    • 비어있는 필드들의 값은 Imputer 함수를 활용하여 채워넣어야함.
  • Feature Extractor

 

문자 카테고리형 데이터 처리

  • StringIndexer, OneHotEncoder  :텍스트 카테고리를 숫자로 변환
  • 왼쪽과 같은 값을 갖는 Color라는 이름의 피쳐가 존재한다면 이를 오른쪽과 같은 숫자로 변환

  • Scikit-Learn은 sklearn.preprocessing 모듈 아래 여러 인코더 존재
    • OneHotEncoder, LabelEncoder, OrdinalEncoder, ...
  • Spark MLlib의 경우 pyspark.ml.feature 모듈 밑에 두 개의 인코더 존재
    • StringIndexer, OneHotEncoder
    • 사용법은 Indexer 모델을 만들고(fit), Indexer 모델로 데이터프레임을 transform

StringIndexer

from pyspark.ml.feature import StringIndexer
gender_indexer = StringIndexer(inputCol='Gender', outputCol='GenderIndexed')
gender_indexer_model = gender_indexer.fit(final_data)
final_data_with_transformed = gender_indexer_model.transform(final_data)
  • 아래 처럼 리스트를 사용하여 한번에 여러개의 컬럼을 인코딩할 수 있다.
    • 차이점은 복수의 컬럼을 넣어줄 때는 인자이름이 inputCols, outputCols로 끝에 's'를 붙여주어야 한다.
from pyspark.ml.feature import StringIndexer
category_indexor = StringIndexer(inputCols=['Gender','Embarked'], outputCols=['GenderIndexed','EmbarkedIndexed'])
category_indexor_model = category_indexor.fit(final_data)
final_data_with_transformed = category_indexor_model.transform(final_data)

CF) Indextostring

  • StringIndexer와 다르게 한번에 여러개의 컬럼을 변환할 수 없다. 즉 하나씩 일일이 바꾸어주어야 한다.
from pyspark.ml.feature import IndexToString
gender_indexer = IndexToString(inputCol='GenderIndexed', outputCol='Gender')
gender_indexer_model = gender_indexer.fit(final_data)
final_data_with_transformed = gender_indexer_model.transform(final_data)

OneHotEncoder

  • Scikit-Learn에서는 문자열 형태의 컬럼을 그대로 넣어주면 알아서 내부적으로 레이블 인코딩을 호출하여 One Hot Vector로 변환
  • 하지만 Spark OneHotEncoder는 문자열에서 숫자로 변환해주는 레이블 인코딩 작업을 필수로 수행해주어야 함.
  • dropLast : True로 설정하면 one-hot-vector로 변환시 마지막 백터를 드랍한다.
    • 모든 원소가 0일때도 하나의 값을 나타낼 수 있기 때문이기에, True로 설정하면 마지막 백터를 드랍한다.
변수의 인자 dropLast = False dropLast = True
Red [1,0,0] [1,0]
Orange [0,1,0] [0,1]
Blue [0,0,1] [0,0]
from pyspark.ml.feature import StringIndexer, OneHotEncoder
category_indexor = StringIndexer(inputCols=['Gender','Embarked'], outputCols=['GenderIndexed','EmbarkedIndexed'])
category_indexor_data = category_indexor.fit(final_data).transform(final_data)
one_hot_encoder = OneHotEncoder(inputCols=['GenderIndexed','EmbarkedIndexed'], outputCols=['Gender_onehot','Embarked_onehot'], dropLast=True)
encoding_df = one_hot_encoder.fit(category_indexor_data).transform(category_indexor_data)
encoding_df.show()

 

Scaling

  • 숫자 필드 값의 범위를 특정 범위(예를 들면 0부터 1)로 변환하는 것
  • 피쳐 스케일링 (Feature Scaling) 혹은 정규화 (Normalization)라 부름
  • 사용법은 Scaler 모델을 만들고(fit), Scaler 모델로 데이터프레임을 transform
  • StandardScaler
    • 각 값에서 평균을 빼고 이를 표준편차로 나눔.
    • 값의 분포가 정규분포를 따르는 경우 사용
  • MinMaxScaler
    • 모든 값을 0과 1사이로 스케일. 각 값에서 최소값을 빼고 (최대값-최소값)으로 나눔

StandardScaler

  • WithMean, withStd인자를 True로 지정하면 평균이 0, 표준편차가 1인 표준정규분포형태로 값 Scaling
  • False로 설정하면 수치형 값들의 실제 평균값으로 설정하여 정규화 수행
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.feature import StandardScaler, MinMaxScaler

assembler = VectorAssembler(inputCols=['Pclass', 'SibSp', 'Parch', 'Fare', 'AgeImputed', 'GenderIndexed'], outputCol='features')
data_vec = assembler.transform(final_data)
scaler = StandardScaler(inputCol = 'features', outputCol = 'feature_scaled', withMean=True, widStd=True)
df_scaled = scaler.fit(data_vec).transform(data_vec)
df_scaled.show()

MinMaxScaler

  • 인자로 min값과 max값을 직접 지정할 수 있다. 
  • Default : min ->0, max -> 1
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.feature import StandardScaler, MinMaxScaler

assembler = VectorAssembler(inputCols=['Pclass', 'SibSp', 'Parch', 'Fare', 'AgeImputed', 'GenderIndexed'], outputCol='features')
data_vec = assembler.transform(final_data)
scaler = MinMaxScaler(inputCol = 'features', outputCol = 'feature_scaled', min=0, max=1)
df_scaled = scaler.fit(data_vec).transform(data_vec)
df_scaled.show()

 

Null값 채우기

  • 값이 존재하지 않는 레코드들이 존재하는 필드들의 경우 기본값을 정해서 채우는 것. Impute한다고 부름

  • Scikit-Learn은 sklearn.preprocessing 모듈 아래 존재
    • Imputer
  • Spark MLlib의 경우 pyspark.ml.feature 모듈 밑에 존재
    • Imputer
    • 사용법은 Imputer 모델을 만들고(fit), Imputer 모델로 데이터프레임을 transform
from pyspark.ml.feature import Imputer
imputer = Imputer(strategy='mean', inputCols=['Age'], outputCols=['AgeImputed'])
imputer_model = imputer.fit(final_data)
final_data_age_transformed = imputer_model.transform(final_data)
728x90
반응형