ASAC 빅데이터 분석가 7기/ASAC 일일 기록

ASAC 빅데이터 분석가 과정 36일차 (25.01.24)

junslee 2025. 1. 24. 09:30

5_ML

2_code

4_reg

!gdown 1hSR9xEUuMfibmPsYBkJugActrUp72rf4
!gdown 1A8o82PKNIqWZNwx3ytS5Uz95tt6cRn34
# 필요한 패키지
import pandas as pd
import numpy as np
# 간단한 EDA
import matplotlib.pyplot as plt
import seaborn as sns
# 데이터 처리
from sklearn.model_selection import train_test_split
# + 파이썬 통계 관련 간단히 체크 : 파이썬에 간한 통계 처리
# => 공식적인 부분을 하기 위해서는 전통적인 통계 패키지로 처리한 값!
# R/SAS/SPSS etc [ 공식적인 부분에서는 전문 프로그램으로 처리한 수치
import scipy.stats as stats
  • 주의사항
    => test 는 내가 한 번도 보지 못한 데이터가 있을 수 있다.
    test에서는 train에서 처리한 기준 그래도 적용만 해야 한다.
    but) train에서 없는 현상/값들이 test에서 발생할 수도 있다.
    -> 코드적으로 처리를 할지 고민하자

train_path = '/content/train.csv'
test_path = '/content/test.csv'
train_df = pd.read_csv(train_path)
test_df = pd.read_csv(test_path)
train_df.head()

test_df.head()

train_df.shape
(1460, 81)

  • 컬럼이 80개 아주 작은 편
  • FM : 80개 컬럼에 대해서 다 EDA를 진행을 해야 한다.
    : 반도체쪽 플젝( 컬럼이 수백개 정도 ) 파악하는데 좀 걸림 FM
    => AM 처리하는 입장 : 중요한 변수들을 중심 -> DT/lgihtGBM FI을 활용해서
  • 플젝 : 변수가 적을 수 있는데 실제 일은 변수가 너무 많아서 문제
    """
    MSSubClass : 매매와 관련된 주거 타입 식별
    MSZoning : 매매의 일반적인 지역 분류
    LotFrontage : 부동산과 연결된 도로의 선형 피트
    LotArea : 평방피트 단위의 부지 크기
    Street : 부동산으로의 도로(street) 접근 유형
    Alley : 부동산으로의 골목(alley) 접근 유형
    LotShape : 부동산의 일반적인 모양
    LandContour : 부동산의 평탄도
    Utilities : 사용 가능한 유틸리티(수도전기가스) 유형
    LotConfig : 지역 구성
    LandSlope : 부동산의 경사
    Neighborhood : 에임스 시 경계 내의 물리적인 위치
    Condition1 : 주요 도로 및 철도와의 근접성
    Condition2 : 주요 도로 및 철도와의 근접성 (두 개 이상 존재하는 경우)
    BldgType : 주거 유형
    HouseStyle : 주거 스타일
    OverallQual : 전체적인 재료 및 마감 등급
    OverallCond : 집의 전체적인 상태 등급
    YearBuilt : 원래 공사일
    YearRemodAdd : 리모델링 날짜 (리모델링 혹은 추가가 없었던 경우 공사일과 동일)
    RoofStyle : 지붕 유형
    RoofMatl : 지붕 재료
    Exterior 1st : 주택 외장재
    Exterior 2nd : 주택 외장재 (두 개 이상 존재하는 경우)
    MasVnrType : 벽돌 베니어 유형
    MasVnrArea : 벽돌 베니어 면적 (평방피트)
    ExterQual : 외장재 품질
    ExterCond : 외장재 현재 상태
    Foundation : 토대 유형
    BsmtQual : 지하의 높이 평가
    BsmtCond : 지하실 일반적인 상태 평가
    BsmtExposure : 워크아웃 혹은 정원 수준의 벽
    BsmtFinType1 : 지하 마감면의 품질
    BsmtSF1 : 유형 1 마감 평방피트
    BsmtFinType2 : 지하 마감면의 품질 (있는 경우)
    BsmtSF2 : 유형 2 마감 평방피트
    BsmtUnfSF : 마감되지 않은 지하실 면적
    TotalBsmtSF : 지하 총 평방피트
    Heating : 난방 유형
    HeatingQC : 난방 품질 및 상태
    CentralAir : 중앙 에어컨 여부
    Electrial : 전기 시스템
    1stFlrSF : 1층 평방피트
    2ndFlrSF : 2층 평방피트
    LowQualFinSF : 저품질 마감 평방 피트 (모든 층)
    GrLivArea : 지상 거실 면적 평방 피트
    BsmtFullBath : 지하 전체 욕실
    BsmtHalfBath : 지하 반 욕실
    FullBath : 지하층 위의 전체 욕실
    HalfBath : 지하층 위의 반 욕실
    Bedroom : 지하층 위의 침실 수 (지하 침실은 포함하지 않음)
    Kitchen : 지하층 위의 주방 수
    KitchenQual : 주방 품질
    TotRmsAbvGra : 지하층 위의 모든 방 (욕실 제외)
    Functional : 집 기능 (공제가 보장되지 않는 한 일반적인 경우 가정)
    FirePlace : 벽난로 수
    FireplaceQu : 벽난로 품질
    GarageType : 차고 위치
    GarageYrBlt : 차고 건설 연도
    GarageFinish : 차고 내부 마감
    GarageCars : 차량 수용 가능 차고 크기
    GarageArea : 차고 평방피트
    GarageQual : 차고 품질
    GarageCond : 차고 상태
    PavedDrive : 포장된 진입로
    WoodDeckSF : 평방피트 단위의 목재 데크 면적
    OpenPochSF : 평방피트 단위의 개방 현관 면적
    EnclosedPorch : 평방피트 단위의 닫힌 현관 면적
    3SnPorch : 평방 피트의 세 계절 현관 면적
    ScreenPorch : 평방피트 단위의 스크린 현관 면적
    PoolArea : 평방피트 단위의 수영장 면적
    PoolQC : 수영장 품질
    Fence : 울타리 품질
    MiscFeature : 다른 항목에서 다루지 않는 기타 특징
    MiscVal : 기타 특징의 가치
    MoSold : 월 판매
    YrSold : 연 판매
    SaleType : 판매 유형
    SaleCondition : 판매 상태
    """

 

  • 참고) 한국 아파트, 주택 가격 예측 프로젝트 / 주식 가격 예측 프로젝트
    => 뻔한 주제
    + 한국 데이터가 같은 경우에서는 아파트에 대한 상세 정보X [특징이 부족할 수 있다]
    + 누구나 잘 아는 주제 : 듣는 사람들이 다 본인 뇌피셜로 막 이야기/질문
     : 듣는 사람들의 주관을 파악하면서 본인 논리로 끌고가야 한다.
    => 논리구조 끌고가는냐 발표력
    * 면접에서도 직접 발표를 하고 해야 한다. -> 지원포지션+다른포지션

1. 이상치들에 대해 확인

  • 회귀분석같은 경우에서는 더 특별하게 이상치 처리를 신경써야 한다.

  • 참고) 대회에 따라서는 아웃라이에 대해서 감점을 타이트하게 하는 대회
    중요한 이슈
  • Traget : salePrice 주택 가격
sns.lmplot( data = train_df, y="SalePrice", x ="GrLivArea")

  • GrLivArea : 면적 4000초과 하는 데이터는 아웃라이어라고 생각을 하고
     : 저는 지우도록 선택을 하겠습니다
    => 확인 조건에 대한 필터링 -> 불리언 인덱싱
train_df[ train_df["GrLivArea"]>4000]

train_df[ train_df["GrLivArea"]>4000].index
Index([523, 691, 1182, 1298], dtype='int64')

  • 아웃라이어로 판단을 해서 train_df에서 제거를 하겠다
    => drop + 특정 조건을 만족하는 친구들 제거
train_df.drop( train_df[ train_df["GrLivArea"]>4000].index, inplace=True)
sns.lmplot( data = train_df, y="SalePrice", x ="GrLivArea")


  • 분석자의 의견 : 아웃라이에 대한 판단 분석자가 알아서 해야 한다.
     boxplot, 분포 : 위와 같이 시각화+ 도멘인지식
    => 이상치에 대해서 처리를 상당히 중요한 이슈
    참고) 아웃라이어들을 잘 탐지 : 사기검출, VVIP, etc

2. Trarget 체크

sns.histplot(train_df["SalePrice"])

  • mnist : 0~9분포 -> 대충 엇비슷하게 분포
    => 평가 지표(accuracy) + 학습의 방향성(k-fold, train_test split etc)
    => 어느 정도 균일할 떄에는 별로 큰 문제/ 신경쓸 부분이 아주 크지는 않다.

  • 회귀 : 전통 통계 모형들이 정규분포성을 가정을 하기에 y값 의 분포
     : 현실적인 y값들을 모아보면 정규분포 거의 없다.
     : 한쪽으로 쏠리는 경우가 주된 경우

  • 회귀쪽에서 주로 한 쪽에 쏠린 데이터가 있을 때 log 변환
    log1p : log(input+1) -> np.log1p(x)
    0을 log 변환을 해도 0으로 초기/최소값을 연결을 해주기 위해서

  • 참고) 로그 변환의 장점
    1. 값의 변동 대역을 줄여서 오차가 적은 모델을 만들어서 생성 : 스케일다운
    2. 값의 분포가 한 쪽으로 쏠린 경우 : 약간 조정을 해줄 수 있다.
    + 전통 통계쪽 모델은 정규분포 가정
    + 트리기반은 아주 심하지 않아서 크게까지는
train_df.loc[:3,"SalePrice"]

np.log1p(train_df.loc[:3,"SalePrice"])

  • train 정답을 log변환을 해
train_df["SalePrice"] = np.log1p( train_df["SalePrice"])
sns.histplot( train_df["SalePrice"])

  • 참고) 정규성이 어느 정도 되는지 등등 계량화로 할 수 있는 것도 있다.
    => y 값 자체의 분포가 좀 쏠림이 완화가 되었다

  • 참고) 비대칭적인 분포 : log변환, root변환
    => box-cox etc 변환 ( 정규성 )

  • 이런 식으로 컬럼이 많은 경우에 있어서 pairplot 이런 그래프 그리면 pc 랙걸림
    -> 샘플링을 해서 특정한 컬러만 지정해야 한다.

 

# 1. 상관관계가 높은 것들을 위주로 보겠다
# ( 참고 : 모델을 사용을 tree 주요 변수를 선택해서 볼 수도 있고)
corr_train = train_df.corr(numeric_only=True)

# 2. 38개 컬럼을 어느 세월에 체크를
# => 제일 상관계수가 큰 10개만 보자
num = 10
col = corr_train.nlargest(num, "SalePrice" )["SalePrice"].index
coeff = np.corrcoef(  train_df[col].values.T)
# heatmap으로 사용을 해서 시각적으로 corr 높은 것은 색상
sns.heatmap(coeff, annot=True ,
            xticklabels=col.values,
            yticklabels=col.values)


이런 부분들을 바탕으로 EDA를 진행을 하시는데 도구
 : 코드적인 부분 + 도메인 지식 ( 코드가 버벅거리면 탐색을 못 한다.)
 : 데이터 핸들링에 대한 코드가 수월해야 한다.
skip
+ 포폴에서는 이 친구가 데이터를 참 열심히 들여다 봤구나
모델의 성능과 연관을 하면서 처리 결과들을 포폴로 정리
=> 아 내가 이 일이 맞을까, 이 도메인이 맞을까
정답이 없는 문제들을 스스로 해쳐나가야 하고 기준도 없다.
+ 연봉을 많이 주면, 무시하고 할 수 있다.
  • 기술적으로만 처리들을 해나가겠습니다
train_df.head()

  • 최종 kaggle에 제출을 하기 위해서는 문제 번호를 남겨 둬야 해서
    => kaggle에서 sample_submission.csv 파일 참조
train_id = train_df.loc[:,"Id"] # 무쓸모
test_id  = test_df.loc[:,"Id"] # 정답지 제출할 때 사용
# => train의 문항 번호, test 문항 번호
# 위의 ID컬럼은 전혀 학습과/문제 푸는것과 무관하니 제거
train_df.drop("Id", axis=1, inplace=True)
test_df.drop("Id", axis=1, inplace=True)
print(train_df.shape)
print(test_df.shape)
(1456, 80)
(1459, 79)

  • train에 있는 정답지를 분리를 하자 -> Only train에만 하면 된다.
y_df = train_df.loc[:,"SalePrice"]
train_df.drop("SalePrice", axis=1, inplace = True)
print(train_df.shape)
print(test_df.shape)
(1456, 79)
(1459, 79)
  • train_df를 파악
train_df.info()
# -> 가로줄 인덱스가 중간 중간 이빨이 빠져 있다

  • 누락된 데이터들에 대해서 체크
train_df.isnull().sum()

# train : 누락된 데이터의 비율
train_ms = pd.DataFrame( train_df.isnull().sum(), columns=["MissCount"])
# -> 누락된 데이터가 1개 이산인 것들만 보자
train_ms = train_ms[ train_ms["MissCount"]>0]
# -> 누락된 비율로 컬럼
train_ms["MissPrecent"]= (train_ms["MissCount"]/len(train_df) )*100
# -> 순서대로 정렬을 해서 보자 : 내림차순
train_ms.sort_values( by="MissPrecent", ascending=False)

# test : 누락된 데이터의 비율
test_ms = pd.DataFrame( test_df.isnull().sum(), columns=["MissCount"])
# -> 누락된 데이터가 1개 이산인 것들만 보자
test_ms = test_ms[ test_ms["MissCount"]>0]
# -> 누락된 비율로 컬럼
test_ms["MissPrecent"]= (test_ms["MissCount"]/len(test_df) )*100
# -> 순서대로 정렬을 해서 보자 : 내림차순
test_ms.sort_values( by="MissPrecent", ascending=False)


  • train/test 모두 제일 많은 정보가 없는 컬럼들은 거의 유사하다.
    : 모든 train에서 누락되지 않은 컬럼들이 test에서는 누락이 될 수도 있다.
  • train 에서 변형을 하면 동일한 기준을 test 그대로 적용

1. 빵구난 데이터들을 채우자 : 문자형 컬럼 -> None 문자열

# 하나씩 보면서 처리를 검토를 해야 한다.  리스트업
nones = ['PoolQC', 'MiscFeature', 'Alley','Fence', 'FireplaceQu', 'GarageType','GarageFinish',
        'GarageQual','GarageCond','BsmtQual','BsmtCond','BsmtExposure','BsmtFinType1','BsmtFinType2',
        'MasVnrType']
# => train/test모두 "혹시" 누락이 되면 None 값으로 채우자.
# 동일한 채움에 대한 기준을 train/test 모두 적용
for col in nones:
    train_df.fillna( {col:"None"}, inplace = True)
    test_df.fillna( {col:"None"}, inplace = True)
# 누락된 데이터를 채울 때 : 수치형 -> 0으로 일괄 처리
zeros = ['GarageYrBlt','GarageArea','GarageCars','BsmtFinSF1','BsmtFinSF2','BsmtUnfSF','TotalBsmtSF',
         'BsmtFullBath','BsmtHalfBath','MasVnrArea']
for col in zeros:
    train_df.fillna( {col:0}, inplace = True)
    test_df.fillna( {col:0}, inplace = True)
  • => 목적 : train/test에 동일한 기준을 적용한다
# Utilities 컬럼을 체크
train_df["Utilities"].value_counts()

test_df["Utilities"].value_counts()

  • => 불필요한 컬럼인 경우들에 대해서는 제거
    train에서 지울 것이라고 판단을 했다고 하면 test에서도 지워야 한다.
train_df.drop("Utilities", axis=1, inplace=True)
test_df.drop("Utilities", axis=1, inplace=True)
print(train_df.shape)
print(test_df.shape)
(1456, 78)
(1459, 78)
  • train의 값을 기준으로 계산을 해서(규칙) -> 채우겠다
train_df["MSZoning"].value_counts()

test_df["MSZoning"].value_counts()

  • train에서는 누락된 데이터가 없고, test에서는 4건의 누락치가
  • 특정한 값으로 채우겠다 : 기준은 train에서 최빈값
  • 최빈값을 기준으로 혹시 누락되면 채우겠다, 기준 : train에서 찾아야 한다.
train_df["MSZoning"].value_counts().index[0]
'RL'
train_df["MSZoning"].mode()[0] # skip
'RL'
  • 누락 데이터가 있다면 : train의 그 컬럼의 최빈값을 기준으로 채워보자
freq = ['MSZoning','Exterior1st',
        'Exterior2nd','SaleType','Electrical',
        'KitchenQual','Functional']
for col in freq:
    train_df.fillna( {col : train_df[col].mode()[0]}, inplace=True)
    test_df.fillna( {col : train_df[col].mode()[0]}, inplace=True)
# => 코드에러로 나타나는 부분이 아니라 코드 검수를 통해서 치팅에 대한 코드

  • 누락된 데이터들을 처리하는 방법들에 대해서
    1) 임의의 값으로 채운다 : 0, 99, None, etc
    2) 대표값으로 채운다 : 분포/특징 체크를 해서 평균, 중앙값, 최빈값 etc
    => 대표값을 무엇으로 할지에 따라서 조금 결과가 다르다.
    => 기준 : train에 있는 값만 가지고 기준을 찾아야 한다.
    적용 : train/test에 모두 train에서 찾은 기준을 적용
    3) + 유사한 데이터들을 묶어서 // 그룹화를 해서 대표값을 생성
    => 대회에서 상위 랭커들이 주로 사용하는 방법 중 하나
    4) + 수업시간에서는 안 하지만 train 데이터를 바탕으로 결측 컬럼y,
    남은 컬럼 X
    => 결측 컬럼의 값을 예측하는 모델을 만들어서 "예측값" 채울 수 있다.
    etc
    현실적으로 결측치가 이슈가 되는 부분

  • train 데이터를 기반을 뭔가를 해야한다. -> 기준을 설정하는 부분에서
    목적 : LotFrontage
    => train/ test거의 15~17프로 누락 컬럼
    대표값/하나의 값 없음으로 채우기에는 좀 애매한 상황
    => 유사한 데이터를 기반으로 채워주려고 한다.
train_df["old_LotFrontage"] = train_df["LotFrontage"]
train_df.head()


  • 목적 : 비숫한 데이터를 기반으로 대표값을 추출해서 -> 누락데이터를 채우자
    LotFrontage : 건물하고 연결된 도로의 면적
    Neighborhood : 경계내에의 물리적인 위치
    -> LotFrontage 200개 정도의 누락된 데이터를 Neighborhood 값을 기준으로
  • 묶어서 유사한 물리적인 위치에 있는 데이터들을 바탕으로 "대표값"
    + 참고) 유사한 샘플을 보고 : knn 기반으로 하실 수도

  • 할 일 : train_df을 기준으로 해서..
    => Neighborhood컬럼의 값을 통해서 groupby
    그룹별로 대표값을 선정해서 LotFrontage 결측값을 채우자
len(train_df["Neighborhood"].value_counts())
25
train_df.groupby(by = "Neighborhood")["LotFrontage"].agg("median")


  • train_df에서는 바로 해도 된다.
    -> trainsform 사용해서 특정한 조건에 맞는 경우만 처리
    방법은 여러가지인데 구글링을 하다보면,,이런 스타일이 있다.
train_df["LotFrontage"] = train_df.groupby(by = "Neighborhood")["LotFrontage"].transform(
    lambda x:x.fillna(x.median())
)
train_df.head()

train_df["LotFrontage"].isnull().sum()
0
train_df["old_LotFrontage"].isnull().sum()
259
train_df[train_df["old_LotFrontage"].isnull() ].loc[:, ["Neighborhood",
                                                        "LotFrontage",
                                                        "old_LotFrontage"]]

  • train 데이터를 기준으로 그룹별로 대표값을 계산해서 결측치를
    주어진 조건에 따라서 다르게 채우게 된다.
  • 위의 기준으로 test에 결측치가 있다면 이러한 기준으로 채우자
    => merge 사용을 해서 처리하자.

  • test에 LotFrontage 컬럼의 결측치를 채우자
    => train 에서 Neighborhood 바탕으로 그룹으로 대표값을 찾은 값으로 채우자
  • 기준 : train 데이터에서 찾은 기준을 test에 적용하자
test_df["old_LotFrontage"] = test_df["LotFrontage"]
test_df = pd.merge(test_df,ref_table,
                   how="left",
                   left_on="Neighborhood",
                   right_on="Neighborhood"
                   )
test_df.head()
# ref_table : grouopby -> 유니크한값 n:m

  • 확인을 좀 해보자
test_df.loc[ test_df["LotFrontage_x"].isnull(), ["Neighborhood",
                                                 "LotFrontage_x",
                                                 "LotFrontage_y",
                                                 "old_LotFrontage"]]

  • test_df에서 LotFrontage 컬럼이 누락이 된 경우만 채울려고 한다.
test_df.loc[test_df["LotFrontage_x"].isnull(), "LotFrontage_x"] = test_df.loc[test_df["LotFrontage_x"].isnull(), "LotFrontage_y"]
# test_df에서 참조한 컬럼은 제거
test_df.drop("LotFrontage_y", axis=1, inplace=True)
# 컬럼명이 merge 하면서 첨자가 붙어서 다시 train과 동일한 이름으로 변경
# 컬럼명을 변경 : rename
test_df.rename( columns ={"LotFrontage_x" : "LotFrontage"}, inplace=True)
test_df.head()

test_df.head(10)

  • => 앞에서 혹시 몰라서 원본의 LotGrontage 컬럼의 값을 복사, 제거
train_df.drop("old_LotFrontage", axis=1, inplace=True)
test_df.drop("old_LotFrontage", axis=1, inplace=True)
print(train_df.shape)
print(test_df.shape)
(1456, 78)
(1459, 78)
train_df["LotFrontage"].isnull().sum()
0
test_df["LotFrontage"].isnull().sum()
0

  • => 모델을 돌리기위 한 필수 조건 중 2가지(결측치 없어야 하고, 숫자로)
    1. 누락된 데이터 처리 => train 기준
    2. 인코딩(숫자) => unseen data처리 신경
     : one-hot-encoding 하면 신경쓸 부분이 있습니다
from sklearn.preprocessing import LabelEncoder
ordinals = ['LotShape','LandSlope','OverallQual','OverallCond','ExterQual','ExterCond','BsmtQual',
           'BsmtCond','BsmtExposure','BsmtFinType1','BsmtFinType2','HeatingQC','Electrical','KitchenQual',
            'Functional','FireplaceQu','GarageFinish','GarageQual','GarageCond','PavedDrive','PoolQC','Fence']
for col in ordinals:
    # 컬럼별로 정수값을 부여할 규칙( sklearn : 모델처럼)
    le = LabelEncoder()
    # 그 컬럼에서 대해서 규칙 => 기준 : train
    le.fit(train_df[col])
    # train_df는 train_df에서 학습한 룰 대로 적용만 하면 된다.
    # col : A ->0, B ->1, C ->2
    train_df[col] = le.transform(train_df[col])
    # test_df에다가도 그냥 적용을 하면
    # B,C, D -> D?

    #####################################################
    # + test_df 에서는 unseen 값이 나타나면 어떻게 할지 코드로
    prev_classses = list(le.classes_)
    # 신규 test의 unseen data  대한 종류를 "뒤"로 추가
    for label in np.unique(test_df[col]):
        if label not in prev_classses: # unseen
            prev_classses.append( label )
    le.classes_ = np.array( prev_classses )
    ####################################################
    # => unseen data 처
    test_df[col] = le.transform(test_df[col])
print(train_df.shape)
print(test_df.shape)
(1456, 78)
(1459, 78)

  • 원핫인코딩 적용할 때 : unseen data 처리에 신경을 더 써야 한다.
    1) train/test에서 생성되는 컬럼의 값이 다를 수 있다.
    1-1) train에만 있고, test에는 없는 항목   : 0으로 채워서 test 추가
    1-2) train에는 없고, test에만 생성한 항목 : test에서 컬럼을 제거
    2) train/test의 컬럼의 순서가 다를 수 있다. => 순서를 정리
nominals = ['MSSubClass','MSZoning','Street','Alley','LandContour','LotConfig','Neighborhood','Condition1','Condition2','BldgType','HouseStyle','RoofStyle','RoofMatl',
           'Exterior1st','Exterior2nd','MasVnrType','Foundation','Heating','CentralAir','GarageType','MiscFeature','SaleType','SaleCondition','MoSold','YrSold']

  • 참고) sklearn 라벨인코딩 -> 원핫인코딩 : 변환 귀찮음
    간단하게 하기 위해서 : pandas의 get_dummies() 메서드를 활용할 수 있다.
    => 순서와 컬럼이 순서가 꼬일 수 있다. 정리
train_df = pd.get_dummies( train_df, columns=nominals, prefix_sep="_")
test_df = pd.get_dummies( test_df, columns=nominals, prefix_sep="_")
print(train_df.shape)
print(test_df.shape)
(1456, 248)
(1459, 236)

  • -> 간단하게 get_dummies()이용해서 컬럼을 펼치면 모양이 쪽날 수 있다.
train_df.head()

test_df.head()

  • 처리할 컬럼들에 대해서 리스트업 
    => train_df에서 get_dummies() 생성된 컬럼들을 기준
    규칙 : 컬럼명에 _ 포함, 앞에 이름이 있어야 한다.
    => nomial 변수들 중에서 get_dummies() 로 생성된 컬럼들리스트
cat_dummies = [ col for col in train_df if "_" in col and col.split("_")[0] in nominals]
cat_dummies

for col in train_df:
    print(col)
# => 컬럼을 중심으로 돌리게 된다
# 출력 생략

train_df에서 처리할 컬럼들을 추출 cat_dummies

# case1) train에만 존재하고, test에는 없는 경우
# => test에 컬럼을 추가 & 값을 0으로 일괄 채우자
for col in cat_dummies:
    if col not in test_df.columns: # -> train에만 추가된 컬럼
        print("test에 컬럼 추가:", col)
        test_df[col] = 0
# case2) test에만 존재하고, train에는 없는 unseen data 에대한 부분
# => test에서 컬럼을 제거하면 끝
for col in test_df.columns:
    if ("_" in col)  and ( col.split("_")[0] in nominals) and (col not in cat_dummies):
        # unseen data --> test_df만 추가가 된 새로운 컬럼 : 제거
        print("test에 컬럼 제거:", col)
        test_df.drop(col, axis=1, inplace=True)

print(train_df.shape)
print(test_df.shape)
(1456, 248)
(1459, 248)
  • => 끝이 아니라 주의 해야 한다.
    컬럼의 순서가 train/test가 서로 다를 수 있다.
    컬럼의 수는 동일해도, train과 test의 컬럼의 순서가 다를 수 있다.

  • train_df.columns
  • test_df.columns

  • + opt) 숫자값들에 대해서 조정 scaler (정규화)
    0~255 : 0~1사이의 값으로 조정 min_max_scaleer -> 양수
    : 평균/표준편차 standard_scaler -> 0을 + /- ( 정규화 )
    => 이 외엥도 여러가지 값을 조정하는 방식이 있다.
    참고) tree기반의 모형들을 굳이 잘 신경을 안 쓰기도 한다.
  • from sklearn.preprocessing import StandardScaler

  • => 컬럼별 값을 대상으로 평균/ 표준편차
    train값을 정규화 -> test 적용
  • train_df에서 값을 바탕으로 기준 설정/학습
scaler = StandardScaler()
scaler.fit(train_df)

  • train_df에 적용
X_train = scaler.transform( train_df)
X_train = pd.DataFrame(X_train, columns =train_df.columns )
  • test_df에 적용
    => train_df에서 찾은 mean/std 그대로 적용만
    + 컬럼의 순서가 틀어졌습니다
test_df = pd.DataFrame( test_df, columns = train_df.columns)
X_test = scaler.transform( test_df)
X_test = pd.DataFrame(X_test, columns =train_df.columns )
  • X_train.head()

  • X_test.head()

# 모델을 돌리기 위한 기본 조건만 처리를 한다.

목적 : 데이터의 전처리를 정말 간단하게 하면 끝도 없이 간단하게 할 수 있다.
정교하게 한다면, 상당히 복잡할 수 있다.
: 컬럼들이 많아서 규칙화를 다 코드화작업 pandas의 수월하게 사용
규칙/코드화
=> 얼마나 잘 하고, 어떻게 하느냐 Feature(다양한 아이디어+도메인)
+ 뒤에 모델링은 상당히 루틴한 작업
+ 뒤에 모델 돌리는 부분
+ 클라우드 anaconda + jupyter notebook 환경세팅