데이터 파편화 문제 - 명시적인 키변수가 있는 경우
.
Data_Preprocessing_TIL(20210711)
[학습자료]
패스트캠퍼스 온라인 강의 “파이썬을 활용한 데이터 전처리 Level UP 올인원 패키지 Online.” 를 공부하고 정리한 내용입니다.
URL : https://fastcampus.co.kr/data_online_preprocess
[학습내용]
- 명시적인 키변수가 있는 경우란
효율적인 데이터베이스 관리를 위해, 가공이 잘 된 데이터임에도 불구하고 데이터가 키 변수를 기준으로 나뉘어져 있는 경우가 흔하다.
- 해결방안
SQL에서는 JOIN을 이용하여 해결하며, python에서는 merge를 이용해서 해결한다.
일반적인 경우는 이런식으로 해결하면 되지만 케이스 바이 케이스이기 때문에 반드시 아래의 두개의 원칙을 기억해야 한다.
원칙 1. 어떤게 키인지 명확하게 확인해야 한다.
어느 컬럼이 키 변수 역할을 하는지 확인하고, 키변수를 통일해야 한다.
원칙 2. 레코드 단위를 명확하게 해야 한다.
- 위에 문제를 해결하기 위해 많이 쓰는 pandas.merge 함수
키변수를 기준으로 두개의 데이터 프레임을 join하는 함수
주요입력
1) left : 병합대상 데이터 프레임 1
2) right : 병합대상 데이터 프레임 2
3) on : 통합기준 key 변수 및 변수리스트
입력하지 않으면 이름이 같은 변수를 key로 식별하기 때문에 명시를 해주는게 좋다.
4) left_on : 데이터 프레임 1의 key 변수 및 변수리스트
5) right_on : 데이터 프레임 2의 key 변수 및 변수리스트
6) left_index : 데이터 프레임 1의 인덱스를 key 변수로 사용할지 여부
7) right_index : 데이터 프레임 2의 인덱스를 key 변수로 사용할지 여부
- 실습
Telco_churn_customer_churn.csv과 Telco_churn_customer_info.csv을 join 해보자
# data 불러오기
import os
import pandas as pd
os.chdir(r"C:/Users/user/Desktop/aa/part-4.-머신러닝을-위한-필수-전처리/Part 4. 머신러닝을 위한 필수 전처리/데이터/")
df1 = pd.read_csv("Telco_churn_customer_churn.csv")
df1
customerID | Churn | |
---|---|---|
0 | 7590-VHVEG | No |
1 | 5575-GNVDE | No |
2 | 3668-QPYBK | Yes |
3 | 7795-CFOCW | No |
4 | 9237-HQITU | Yes |
... | ... | ... |
7038 | 6840-RESVB | No |
7039 | 2234-XADUH | No |
7040 | 4801-JZAZL | No |
7041 | 8361-LTMKD | Yes |
7042 | 3186-AJIEK | No |
7043 rows × 2 columns
df2 = pd.read_csv("Telco_churn_customer_info.csv")
df2
customerID | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | OnlineSecurity | OnlineBackup | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | Female | 0 | Yes | No | 1 | No | No phone service | DSL | No | Yes | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 |
1 | 5575-GNVDE | Male | 0 | No | No | 34 | Yes | No | DSL | Yes | No | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.5 |
2 | 3668-QPYBK | Male | 0 | No | No | 2 | Yes | No | DSL | Yes | Yes | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 |
3 | 7795-CFOCW | Male | 0 | No | No | 45 | No | No phone service | DSL | Yes | No | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 |
4 | 9237-HQITU | Female | 0 | No | No | 2 | Yes | No | Fiber optic | No | No | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 6840-RESVB | Male | 0 | Yes | Yes | 24 | Yes | Yes | DSL | Yes | No | Yes | Yes | Yes | Yes | One year | Yes | Mailed check | 84.80 | 1990.5 |
7039 | 2234-XADUH | Female | 0 | Yes | Yes | 72 | Yes | Yes | Fiber optic | No | Yes | Yes | No | Yes | Yes | One year | Yes | Credit card (automatic) | 103.20 | 7362.9 |
7040 | 4801-JZAZL | Female | 0 | Yes | Yes | 11 | No | No phone service | DSL | Yes | No | No | No | No | No | Month-to-month | Yes | Electronic check | 29.60 | 346.45 |
7041 | 8361-LTMKD | Male | 1 | Yes | No | 4 | Yes | Yes | Fiber optic | No | No | No | No | No | No | Month-to-month | Yes | Mailed check | 74.40 | 306.6 |
7042 | 3186-AJIEK | Male | 0 | No | No | 66 | Yes | No | Fiber optic | Yes | No | Yes | Yes | Yes | Yes | Two year | Yes | Bank transfer (automatic) | 105.65 | 6844.5 |
7043 rows × 20 columns
customerID라는 명확한 키변수가 있는 것을 확인했다 그래서 merge on을 활용해서 join이 가능하다.
# 두 데이터프레임에서 이름이 같은 변수가 key 변수만 있더라도, on을 사용하는 것이 바람직함
merged_df = pd.merge(df1, df2, on = 'customerID')
merged_df
customerID | Churn | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | ... | OnlineBackup | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | No | Female | 0 | Yes | No | 1 | No | No phone service | DSL | ... | Yes | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 |
1 | 5575-GNVDE | No | Male | 0 | No | No | 34 | Yes | No | DSL | ... | No | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.5 |
2 | 3668-QPYBK | Yes | Male | 0 | No | No | 2 | Yes | No | DSL | ... | Yes | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 |
3 | 7795-CFOCW | No | Male | 0 | No | No | 45 | No | No phone service | DSL | ... | No | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 |
4 | 9237-HQITU | Yes | Female | 0 | No | No | 2 | Yes | No | Fiber optic | ... | No | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 6840-RESVB | No | Male | 0 | Yes | Yes | 24 | Yes | Yes | DSL | ... | No | Yes | Yes | Yes | Yes | One year | Yes | Mailed check | 84.80 | 1990.5 |
7039 | 2234-XADUH | No | Female | 0 | Yes | Yes | 72 | Yes | Yes | Fiber optic | ... | Yes | Yes | No | Yes | Yes | One year | Yes | Credit card (automatic) | 103.20 | 7362.9 |
7040 | 4801-JZAZL | No | Female | 0 | Yes | Yes | 11 | No | No phone service | DSL | ... | No | No | No | No | No | Month-to-month | Yes | Electronic check | 29.60 | 346.45 |
7041 | 8361-LTMKD | Yes | Male | 1 | Yes | No | 4 | Yes | Yes | Fiber optic | ... | No | No | No | No | No | Month-to-month | Yes | Mailed check | 74.40 | 306.6 |
7042 | 3186-AJIEK | No | Male | 0 | No | No | 66 | Yes | No | Fiber optic | ... | No | Yes | Yes | Yes | Yes | Two year | Yes | Bank transfer (automatic) | 105.65 | 6844.5 |
7043 rows × 21 columns
이번에는 left_on과 right_on을 이용해서 join을 해보자
# 연습을 위해 df2의 customerID 컬럼명을 ID로 변환해보자
df2.rename({"customerID":"ID"}, axis = 1, inplace = True)
df2
ID | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | OnlineSecurity | OnlineBackup | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | Female | 0 | Yes | No | 1 | No | No phone service | DSL | No | Yes | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 |
1 | 5575-GNVDE | Male | 0 | No | No | 34 | Yes | No | DSL | Yes | No | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.5 |
2 | 3668-QPYBK | Male | 0 | No | No | 2 | Yes | No | DSL | Yes | Yes | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 |
3 | 7795-CFOCW | Male | 0 | No | No | 45 | No | No phone service | DSL | Yes | No | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 |
4 | 9237-HQITU | Female | 0 | No | No | 2 | Yes | No | Fiber optic | No | No | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 6840-RESVB | Male | 0 | Yes | Yes | 24 | Yes | Yes | DSL | Yes | No | Yes | Yes | Yes | Yes | One year | Yes | Mailed check | 84.80 | 1990.5 |
7039 | 2234-XADUH | Female | 0 | Yes | Yes | 72 | Yes | Yes | Fiber optic | No | Yes | Yes | No | Yes | Yes | One year | Yes | Credit card (automatic) | 103.20 | 7362.9 |
7040 | 4801-JZAZL | Female | 0 | Yes | Yes | 11 | No | No phone service | DSL | Yes | No | No | No | No | No | Month-to-month | Yes | Electronic check | 29.60 | 346.45 |
7041 | 8361-LTMKD | Male | 1 | Yes | No | 4 | Yes | Yes | Fiber optic | No | No | No | No | No | No | Month-to-month | Yes | Mailed check | 74.40 | 306.6 |
7042 | 3186-AJIEK | Male | 0 | No | No | 66 | Yes | No | Fiber optic | Yes | No | Yes | Yes | Yes | Yes | Two year | Yes | Bank transfer (automatic) | 105.65 | 6844.5 |
7043 rows × 20 columns
df1.head()
customerID | Churn | |
---|---|---|
0 | 7590-VHVEG | No |
1 | 5575-GNVDE | No |
2 | 3668-QPYBK | Yes |
3 | 7795-CFOCW | No |
4 | 9237-HQITU | Yes |
위와 같이 df2의 customerID가 ID로 바뀐것을 확인할 수 있다.
이때 그러면 pd.merge(df1, df2, on = ‘customerID’) 이거를 쓰게되면
df1에는 customerID가 있는데 df2에는 없어서 제대로 병합이 되지 않을것이다.
이럴때 사용하는게 left_on과 right_on 이다.
어떤 컬럼을 기준으로 병합할건지 명시해서 병합하는 방법이다.
# left, right 순서를 반드시 고려해야 함
# on, left_on, right_on 키워드에 리스트 형태로 입력받을 수 있음 (여기서도 순서가 중요)
merged_df = pd.merge(df1, df2, left_on = ['customerID'], right_on = ['ID'])
# 키 컬럼 두 개가 모두 살아있음
merged_df
customerID | Churn | ID | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | ... | OnlineBackup | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | No | 7590-VHVEG | Female | 0 | Yes | No | 1 | No | No phone service | ... | Yes | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 |
1 | 5575-GNVDE | No | 5575-GNVDE | Male | 0 | No | No | 34 | Yes | No | ... | No | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.5 |
2 | 3668-QPYBK | Yes | 3668-QPYBK | Male | 0 | No | No | 2 | Yes | No | ... | Yes | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 |
3 | 7795-CFOCW | No | 7795-CFOCW | Male | 0 | No | No | 45 | No | No phone service | ... | No | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 |
4 | 9237-HQITU | Yes | 9237-HQITU | Female | 0 | No | No | 2 | Yes | No | ... | No | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7038 | 6840-RESVB | No | 6840-RESVB | Male | 0 | Yes | Yes | 24 | Yes | Yes | ... | No | Yes | Yes | Yes | Yes | One year | Yes | Mailed check | 84.80 | 1990.5 |
7039 | 2234-XADUH | No | 2234-XADUH | Female | 0 | Yes | Yes | 72 | Yes | Yes | ... | Yes | Yes | No | Yes | Yes | One year | Yes | Credit card (automatic) | 103.20 | 7362.9 |
7040 | 4801-JZAZL | No | 4801-JZAZL | Female | 0 | Yes | Yes | 11 | No | No phone service | ... | No | No | No | No | No | Month-to-month | Yes | Electronic check | 29.60 | 346.45 |
7041 | 8361-LTMKD | Yes | 8361-LTMKD | Male | 1 | Yes | No | 4 | Yes | Yes | ... | No | No | No | No | No | Month-to-month | Yes | Mailed check | 74.40 | 306.6 |
7042 | 3186-AJIEK | No | 3186-AJIEK | Male | 0 | No | No | 66 | Yes | No | ... | No | Yes | Yes | Yes | Yes | Two year | Yes | Bank transfer (automatic) | 105.65 | 6844.5 |
7043 rows × 22 columns
# 키 컬럼 중 하나를 삭제해줘야 함
merged_df.drop('ID', axis = 1, inplace = True)
merged_df.head()
customerID | Churn | gender | SeniorCitizen | Partner | Dependents | tenure | PhoneService | MultipleLines | InternetService | ... | OnlineBackup | DeviceProtection | TechSupport | StreamingTV | StreamingMovies | Contract | PaperlessBilling | PaymentMethod | MonthlyCharges | TotalCharges | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7590-VHVEG | No | Female | 0 | Yes | No | 1 | No | No phone service | DSL | ... | Yes | No | No | No | No | Month-to-month | Yes | Electronic check | 29.85 | 29.85 |
1 | 5575-GNVDE | No | Male | 0 | No | No | 34 | Yes | No | DSL | ... | No | Yes | No | No | No | One year | No | Mailed check | 56.95 | 1889.5 |
2 | 3668-QPYBK | Yes | Male | 0 | No | No | 2 | Yes | No | DSL | ... | Yes | No | No | No | No | Month-to-month | Yes | Mailed check | 53.85 | 108.15 |
3 | 7795-CFOCW | No | Male | 0 | No | No | 45 | No | No phone service | DSL | ... | No | Yes | Yes | No | No | One year | No | Bank transfer (automatic) | 42.30 | 1840.75 |
4 | 9237-HQITU | Yes | Female | 0 | No | No | 2 | Yes | No | Fiber optic | ... | No | No | No | No | No | Month-to-month | Yes | Electronic check | 70.70 | 151.65 |
5 rows × 21 columns