ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SparkML] StandardScaler 알아보기 ( 표준화, Feature Scaling )
    Spark/SparkML 2024. 1. 8. 21:07
    728x90
    반응형

    - 목차

     

    소개.

    이번 소개글에서 SparkML 의 StandardScaler 에 대해서 알아보려고 합니다.

    StandardScaler 는 데이터셋의 feature 를 표준화 관점에서 변경하는 것을 의미합니다.

    그럼 표준화는 무엇일까요 ?

    그래서 먼저 Standardization 인 표준화에 대해서 간단히 알아보겠습니다.

    표준화는 데이터의 분포를 변경하는 행위입니다.

    평균을 0 으로, 그리고 분산을 1 로 설정하여 데이터의 분포를 변경합니다.

    즉, 표준정규분포를 갖도록 재조정됩니다.

     

    표준화의 공식은 아래와 같습니다.

    $$ X^{'}=\frac{X-\mu }{\sigma} $$

    $\sigma$ 은 표준편차를 의미하고, $\mu$ 는 평균을 의미합니다.

     

    Feature Scaling 은 왜 필요할까?.

    표준화 이외에도 Normalization, Regularization 에 해당하는 Feature Scaling 기법들이 더 존재합니다.

    이러한 Feature Scaling 은 전처리 단계에서 모델의 성능을 향상시키기 위해서 사용됩니다.

    만약, Feature 들의 데이터 분포가 제각각인 상황이 발생합니다.

    feature 1 은 0 부터 100 까지의 범위를 가지고, feature 2 는 -10000 부터 +10000 까지 범위를 가진다고 가정할 때에

    feature 1 의 가중치와 feature2 의 가중치는 범위의 차이만큼 차이가 발생할 수 있습니다.

    (0 ~ 100) < (-10000 ~ +10000) 거의 10만 배의 차이를 보이죠.

    경사하강법과 같은 경우에 learning-rate 만큼 Weight 를 조정하여 Loss Function 을 실행하는 구조인데,

    feature 들의 범위의 차이가 매우 크기때문에 비효율적인 Weight 조정 시간이 길어질 확률이 높습니다.

    또한 KNN, SVM 같은 공간 또는 차원에서의 데이터 분포가 중요한 모델의 경우에

    데이터의 분포가 작은 것이 효율적입니다.

     

    Feature Scaling 을 인과관계없이 데이터를 왜곡하는 것이 아니라 데이터의 범위와 분포를 조절합니다.

    따라서 데이터의 의미를 유지하면서 모델에 Fit 한 형태로 변경하는 것입니다.

     

     

    SparkML 로 구현하기.

    0 부터 999 까지 값을 가지는 feature 에 대한 표준화를 수행합니다.

    SparkML 은 StandardScaler 모듈을 통해서 간단히 표준화를 수행할 수 있습니다.

    표준화를 수행하기에 앞서 feature column 을 Vector 형태로 변경이 선행되어야합니다.

    그래서 VectorAssembler 를 사용하여 feature 를 Vector 로 변경합니다.

    import matplotlib.pyplot as plt
    import seaborn as sns
    
    from pyspark.ml.feature import StandardScaler, VectorAssembler
    from pyspark.sql import SparkSession
    from pyspark.sql.functions import col
    from pyspark.sql.types import StructType, StructField, DoubleType, IntegerType
    
    spark = SparkSession.builder.appName("example").master("local[*]") \
        .config("spark.driver.bindAddress", "localhost").getOrCreate()
    
    data = {
        "feature": list(range(0, 1000)),
    }
    plt.figure()
    sns.boxplot(x=data["feature"], palette='Set3')
    
    plt.show()
    
    schema = StructType([StructField("feature", IntegerType(), True)])
    df = spark.createDataFrame(list(zip(*data.values())), schema=schema)
    df = df.withColumn("feature", col("feature").cast(DoubleType()))
    
    df = VectorAssembler(inputCols=["feature"], outputCol="feature_index").transform(df)
    scaler = StandardScaler(inputCol="feature_index", outputCol="scaled_feature", withStd=True, withMean=True)
    scaler_model = scaler.fit(df)
    scaled_df = scaler_model.transform(df)
    
    # DenseVector
    scaled_line = list(map(lambda x: x[0].values[0], scaled_df.select("scaled_feature").collect()))
    sns.boxplot(x=scaled_line, palette='Set3')
    plt.show()

     

    < 표준화 이전 데이터의 boxplot >

     

    < 표준화가 적용된 데이터의 boxplot >

     

    반응형
Designed by Tistory.