해당 내용은 모두연의 프로덕트데이터분석가1기 수료과정 중 내용과 개인적인 내용을 정리한 것입니다.

데이터 병합, 개요 작성, 결측치 및 이상치 처리, 집계와 피벗 테이블 활용, 로그 변환 및 원-핫 인코딩, 스케일링, 주성분 분석(PCA)을 통해 데이터 변환의 고급 기술.
- 데이터를 다양한 방법으로 합치고 변환할 수 있다.
- 데이터의 스케일을 변환할 수 있다.
- 카테고리형 데이터를 숫자형태로 변환할 수 있다.
- 데이터의 차원축소를 할 수 있다.
JOIN 종류: INNER, OUTER, LEFT, RIGHT
INNER JOIN (교집합)
"공통된 데이터만 가져온다"
- A와 B에 모두 존재하는 승객만 선택
- A, B 둘 다 포함된 승객만 출력됨.
예제:
승객 ID / (A)승객 이름
1 | Alice |
2 | Bob |
3 | Charlie |
승객 ID / (B)결제 금액
2 | $20 |
3 | $35 |
4 | $50 |
INNER JOIN 결과:
승객 ID/ 승객 이름 / 결제 금액
2 | Bob | $20 |
3 | Charlie | $35 |
요점: A, B 둘 다 존재하는 데이터만 남김.
LEFT JOIN (A 우선, B가 없어도 포함)
"A(왼쪽)에 있는 데이터는 전부 포함하고, B에 없는 데이터는 NULL로 채운다"
- A 테이블의 모든 승객을 포함
- B 테이블에 없는 승객은 결제 금액을 NULL 처리
예제:
LEFT JOIN 결과:
승객 ID / 승객 이름 / 결제 금액
1 | Alice | NULL |
2 | Bob | $20 |
3 | Charlie | $35 |
요점: A(왼쪽)의 모든 값 유지, B(오른쪽)에 없으면 NULL
RIGHT JOIN (B 우선, A가 없어도 포함)
"B(오른쪽)에 있는 데이터는 전부 포함하고, A에 없는 데이터는 NULL로 채운다"
- B 테이블의 모든 결제를 포함
- A 테이블에 없는 승객은 이름이 NULL 처리
예제:
RIGHT JOIN 결과:
승객 ID / 승객 이름 / 결제 금액
2 | Bob | $20 |
3 | Charlie | $35 |
4 | NULL | $50 |
요점: B(오른쪽)의 모든 값 유지, A(왼쪽)에 없으면 NULL
OUTER JOIN (전체 합집합)
"A, B 모든 데이터 포함하고, 없는 부분은 NULL"
- 모든 승객(A) + 모든 결제(B)
- A 또는 B 중 하나라도 존재하면 포함
예제:
OUTER JOIN 결과:
승객 ID / 승객 이름 / 결제 금액
1 | Alice | NULL |
2 | Bob | $20 |
3 | Charlie | $35 |
4 | NULL | $50 |
요점: A, B 모든 데이터 유지, 없는 부분은 NULL
JOIN 유형 / 설명 / 포함되는 데이터
INNER | 공통 데이터만 포함 | A ∩ B (교집합) |
LEFT | A 우선, B 없으면 NULL | A ⭢ (A + B) |
RIGHT | B 우선, A 없으면 NULL | B ⭢ (A + B) |
OUTER | 전체 포함, 없으면 NULL | A ∪ B (합집합) |
기억하는 방법:
- INNER JOIN = 둘 다 있어야 OK (교집합)
- LEFT JOIN = A는 무조건 포함 (NULL 허용)
- RIGHT JOIN = B는 무조건 포함 (NULL 허용)
- OUTER JOIN = A + B 전부 포함
개요, 결측치&이상치(Missing Value & Outlier), 집계 및 그룹화(Aggregation and Group by), 피벗테이블(Pivot)
salary_df.head()

salary_df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 6684 entries, 0 to 6683
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Age 6680 non-null float64
1 Gender 6684 non-null object
2 Education Level 6684 non-null int64
3 Job Title 6684 non-null object
4 Years of Experience 6684 non-null float64
5 Salary 6684 non-null int64
6 Country 6684 non-null object
7 Race 6684 non-null object
8 Senior 6684 non-null int64
9 CPI 6684 non-null object
dtypes: float64(2), int64(3), object(5)
memory usage: 574.4+ KB
salary_df[
<class 'pandas.core.frame.DataFrame'>
Int64Index: 6684 entries, 0 to 6683
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Age 6680 non-null float64
1 Gender 6684 non-null object
2 Education Level 6684 non-null int64
3 Job Title 6684 non-null object
4 Years of Experience 6684 non-null float64
5 Salary 6684 non-null int64
6 Country 6684 non-null object
7 Race 6684 non-null object
8 Senior 6684 non-null int64
9 CPI 'CPI'] = pd.to_numeric(salary_df['CPI']) #숫자로 바꿔준다
salary_df.describe()
6680.000000 | 6684.000000 | 6684.000000 | 6684.000000 | 6684.000000 | 6684.00000 |
33.611527 | 1.622382 | 8.084007 | 115307.175194 | 0.143477 | 167.12953 |
7.595506 | 0.880474 | 6.097824 | 52806.810881 | 0.350585 | 73.22657 |
21.000000 | 0.000000 | -1.000000 | 350.000000 | 0.000000 | 100.00000 |
28.000000 | 1.000000 | 3.000000 | 70000.000000 | 0.000000 | 132.00000 |
32.000000 | 1.000000 | 7.000000 | 115000.000000 | 0.000000 | 135.30000 |
38.000000 | 2.000000 | 12.000000 | 160000.000000 | 0.000000 | 158.70000 |
62.000000 | 3.000000 | 82.000000 | 250000.000000 | 1.000000 | 307.48000 |
salary_df.isna().sum()
Age 4
Gender 0
Education Level 0
Job Title 0
Years of Experience 0
Salary 0
Country 0
Race 0
Senior 0
CPI 0
dtype: int64
salary_df.isna().mean()
Age 0.000598
Gender 0.000000
Education Level 0.000000
Job Title 0.000000
Years of Experience 0.000000
Salary 0.000000
Country 0.000000
Race 0.000000
Senior 0.000000
CPI 0.000000
dtype: float64
salary_df[salary_df['Age'].isna()] #Age에 결측치가 있는지 알아보는
NaN | Male | 1 | Data Analyst | 3.0 | 130000 | Canada | White | 0 | 158.70 |
NaN | Female | 3 | Project Engineer | 16.0 | 190000 | USA | African American | 1 | 307.48 |
NaN | Female | 1 | Software Engineer | 1.0 | 50000 | Australia | White | 0 | 135.30 |
NaN | Female | 2 | Marketing Coordinator | 8.0 | 85000 | UK | Asian | 0 | 132.00 |
salary_df = salary_df.dropna()
salary_df = salary_df[salary_df['Years of Experience'] != -1]
salary_df['Years of Experience'].sort_values()
4931 0.0
5104 0.0
5115 0.0
5119 0.0
5143 0.0
...
2396 33.0
2391 33.0
2490 34.0
2415 34.0
564 82.0
Name: Years of Experience, Length: 6677, dtype: float64
salary_df[salary_df['Years of Experience'] == 82]
25.0 | Female | 1 | Data Analyst | 82.0 | 110000 | Australia | White | 0 | 135.3 |
salary_df = salary_df[~(salary_df['Years of Experience'] > salary_df['Age'] - 18)]
salary_df.describe()
6674.000000 | 6674.000000 | 6674.000000 | 6674.000000 | 6674.000000 | 6674.000000 |
33.612826 | 1.622116 | 8.076491 | 115294.402307 | 0.143093 | 167.164774 |
7.594369 | 0.880460 | 6.029750 | 52819.326323 | 0.350193 | 73.241730 |
21.000000 | 0.000000 | 0.000000 | 350.000000 | 0.000000 | 100.000000 |
28.000000 | 1.000000 | 3.000000 | 70000.000000 | 0.000000 | 132.000000 |
32.000000 | 1.000000 | 7.000000 | 115000.000000 | 0.000000 | 135.300000 |
38.000000 | 2.000000 | 12.000000 | 160000.000000 | 0.000000 | 158.700000 |
62.000000 | 3.000000 | 34.000000 | 250000.000000 | 1.000000 | 307.480000 |
salary_df[salary_df['Years of Experience'] == 0]
25.0 | Female | 1 | Data Entry Clerk | 0.0 | 35000 | UK | Asian | 0 | 132.00 |
25.0 | Male | 1 | Help Desk Analyst | 0.0 | 35000 | USA | Asian | 0 | 307.48 |
25.0 | Male | 1 | Sales Representative | 0.0 | 30000 | Australia | Asian | 0 | 135.30 |
24.0 | Male | 2 | Back end Developer | 0.0 | 55538 | USA | Asian | 0 | 307.48 |
22.0 | Female | 0 | Back end Developer | 0.0 | 51832 | UK | White | 0 | 132.00 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
24.0 | Female | 0 | Receptionist | 0.0 | 25000 | China | White | 0 | 100.00 |
24.0 | Female | 0 | Receptionist | 0.0 | 25000 | Australia | Australian | 0 | 135.30 |
24.0 | Female | 0 | Receptionist | 0.0 | 25000 | Australia | White | 0 | 135.30 |
24.0 | Female | 0 | Receptionist | 0.0 | 25000 | UK | Welsh | 0 | 132.00 |
24.0 | Female | 0 | Receptionist | 0.0 | 25000 | Australia | Asian | 0 | 135.30 |
120 rows × 10 columns
salary_df.head()
32.0 | Male | 1 | Software Engineer | 5.0 | 90000 | UK | White | 0 | 132.00 |
28.0 | Female | 2 | Data Analyst | 3.0 | 65000 | USA | Hispanic | 0 | 307.48 |
45.0 | Male | 3 | Manager | 15.0 | 150000 | Canada | White | 1 | 158.70 |
36.0 | Female | 1 | Sales Associate | 7.0 | 60000 | USA | Hispanic | 0 | 307.48 |
52.0 | Male | 2 | Director | 20.0 | 200000 | USA | Asian | 0 | 307.48 |
salary_df[salary_df['Gender'] == "Male"]['Salary'].mean()
121383.05728314239
salary_df[salary_df['Gender'] == "Female"]['Salary'].mean()
107873.85405585106
salary_df.groupby('Gender').mean()
32.622008 | 1.600066 | 7.417221 | 107873.854056 | 0.127992 | 167.485166 |
34.425805 | 1.640207 | 8.617430 | 121383.057283 | 0.155483 | 166.901888 |
salary_df.groupby('Gender').max()
60.0 | 3 | Web Developer | 34.0 | 220000 | USA | White | 1 | 307.48 |
62.0 | 3 | Web Developer | 32.0 | 250000 | USA | White | 1 | 307.48 |
salary_df.groupby('Gender')['Salary'].mean()
Gender
Female 107873.854056
Male 121383.057283
Name: Salary, dtype: float64
salary_df.groupby('Gender')['Salary'].sum()
Gender
Female 324484553
Male 444990288
Name: Salary, dtype: int64
salary_df.groupby('Gender')['Salary'].median()
Gender
Female 105000.0
Male 120000.0
Name: Salary, dtype: float64
salary_df.groupby('Gender')['Salary'].std()
Gender
Female 52728.350439
Male 52117.611899
Name: Salary, dtype: float64
salary_df.groupby(['Gender','Country'])['Salary'].mean()
Gender Country
Female Australia 107936.054010
Canada 106884.711340
China 111291.211506
UK 108495.273026
USA 104854.691558
Male Australia 120896.764216
Canada 123973.921516
China 120135.522148
UK 122244.048476
USA 119683.120433
Name: Salary, dtype: float64
salary_df.groupby('Gender')['Salary'].agg(['sum','mean'])
324484553 | 107873.854056 |
444990288 | 121383.057283 |
salary_df.groupby(['Gender','Country'])['Salary'].mean().reset_index()
Female | Australia | 107936.054010 |
Female | Canada | 106884.711340 |
Female | China | 111291.211506 |
Female | UK | 108495.273026 |
Female | USA | 104854.691558 |
Male | Australia | 120896.764216 |
Male | Canada | 123973.921516 |
Male | China | 120135.522148 |
Male | UK | 122244.048476 |
Male | USA | 119683.120433 |
pd.pivot_table(salary_df, index = 'Gender', columns = 'Country', values = 'Salary')
107936.054010 | 106884.711340 | 111291.211506 | 108495.273026 | 104854.691558 |
120896.764216 | 123973.921516 | 120135.522148 | 122244.048476 | 119683.120433 |
pd.pivot_table(salary_df, index = 'Gender', columns = 'Country', values = 'Salary', aggfunc = 'mean')
107936.054010 | 106884.711340 | 111291.211506 | 108495.273026 | 104854.691558 |
120896.764216 | 123973.921516 | 120135.522148 | 122244.048476 | 119683.120433 |
pd.pivot_table(salary_df, index = 'Gender', columns = 'Country', values = 'Salary', aggfunc = np.mean)
107936.054010 | 106884.711340 | 111291.211506 | 108495.273026 | 104854.691558 |
120896.764216 | 123973.921516 | 120135.522148 | 122244.048476 | 119683.120433 |
pd.pivot_table(salary_df, index = 'Gender', columns = 'Country', values = 'Salary', aggfunc = 'sum')
65948929 | 62206902 | 65773106 | 65965126 | 64590490 |
87166567 | 91616728 | 89500964 | 88260203 | 88445826 |
pd.pivot_table(salary_df, index = ['Gender','Race'], columns = 'Country', values = 'Salary', aggfunc = 'sum')
NaN | NaN | NaN | NaN | 15448789.0 |
22620268.0 | 20950962.0 | NaN | 14978857.0 | 17533654.0 |
22623208.0 | NaN | NaN | NaN | NaN |
NaN | 20851624.0 | NaN | NaN | NaN |
NaN | NaN | 20858851.0 | NaN | NaN |
NaN | NaN | NaN | NaN | 14526773.0 |
NaN | NaN | 23853851.0 | NaN | NaN |
NaN | NaN | NaN | 15673240.0 | NaN |
NaN | NaN | NaN | 17882663.0 | NaN |
20705453.0 | 20404316.0 | 21060404.0 | 17430366.0 | 17081274.0 |
NaN | NaN | NaN | NaN | 23910271.0 |
31837948.0 | 31446774.0 | NaN | 24308468.0 | 20421501.0 |
29011770.0 | NaN | NaN | NaN | NaN |
NaN | 30659174.0 | NaN | NaN | NaN |
NaN | NaN | 28164994.0 | NaN | NaN |
NaN | NaN | NaN | NaN | 21025292.0 |
NaN | NaN | 29660738.0 | NaN | NaN |
NaN | NaN | NaN | 23181267.0 | NaN |
NaN | NaN | NaN | 19600032.0 | NaN |
26316849.0 | 29510780.0 | 31675232.0 | 21170436.0 | 23088762.0 |
sales_df = pd.DataFrame({'company': ['a','a','a','a','b','b','b','b'],
'quarter': ['q1','q2','q3','q4','q1','q2','q3','q4'],
'sales': [111,222,333,444,555,666,777,888]})
sales_df
a | q1 | 111 |
a | q2 | 222 |
a | q3 | 333 |
a | q4 | 444 |
b | q1 | 555 |
b | q2 | 666 |
b | q3 | 777 |
b | q4 | 888 |
sales_temp = pd.pivot(sales_df, index = 'company', columns = 'quarter', values = 'sales')
sales_temp.columns = sales_temp.columns.rename('')
new_sales_df = sales_temp.reset_index()
new_sales_df
a | 111 | 222 | 333 | 444 |
b | 555 | 666 | 777 | 888 |
pd.melt(new_sales_df, id_vars = 'company', value_vars = ['q1','q2','q3','q4'], var_name ='quarter' ,value_name = 'sales').sort_values('company')
a | q1 | 111 |
a | q2 | 222 |
a | q3 | 333 |
a | q4 | 444 |
b | q1 | 555 |
b | q2 | 666 |
b | q3 | 777 |
b | q4 | 888 |
주성분 분석 (PCA) (Principal Component Analysis)
1. PCA란?
PCA(주성분 분석, Principal Component Analysis)는 데이터의 차원을 줄이면서도 중요한 정보(변동성)를 최대한 유지하는 기법이다.
즉, 고차원의 데이터를 저차원으로 압축하지만, 핵심 정보를 최대한 유지하려는 방법이다.
2. 왜 PCA가 필요할까?
- 데이터의 차원이 너무 높으면(변수가 많으면) 분석이 어렵고 계산량이 많아진다.
- 차원을 줄이면 데이터 시각화가 쉬워지고, 모델 성능도 개선될 수 있다.
- 데이터에서 가장 중요한 축(주성분)을 찾아 정보를 최대한 보존하면서 단순화할 수 있다.
3. PCA 작동 원리 (한 줄 정리)
데이터의 분포를 따라 가장 중요한 방향(축)을 찾고, 그 축을 기준으로 데이터를 변환(압축)하는 것이다.
4. PCA가 데이터를 변환하는 과정
- 데이터 정규화 (평균 0, 분산 1로 맞춤)
- 변수들의 단위 차이(예: cm, kg)를 맞추기 위해 데이터를 표준화한다.
- 공분산 행렬 계산 (변수 간 관계 분석)
- 어떤 변수들이 함께 변하는지를 확인하여 서로 상관성이 높은 축을 찾는다.
- 고유값 & 고유벡터 계산
- 데이터를 가장 잘 설명하는 새로운 축(주성분)을 찾기 위해 고유값 분해 또는 SVD(특이값 분해)를 수행한다.
- 주성분 선택
- 고유값이 큰 순서대로 가장 중요한 주성분(Principal Components)을 선택한다.
- 보통 전체 정보의 90% 이상을 유지하는 개수의 주성분을 선택한다.
- 데이터 변환 (기존 축 → 주성분 축)
- 기존 변수 대신, 선택한 주성분들로 데이터를 다시 표현하여 차원 축소를 수행한다.
5. PCA를 쉽게 비유하면?
PCA는 사진을 압축하는 과정과 비슷하다.
- 원본 이미지는 고해상도(변수가 많음)
- 하지만 용량이 크면 부담스러우니 적절히 압축하면서 화질(정보)를 최대한 유지해야 한다.
- PCA는 데이터에서 가장 중요한 특징(주성분)만 남기고 나머지는 제거하는 역할을 한다.
6. PCA의 한계
- 주성분이 원래 변수들의 조합이므로, 해석이 어려울 수 있다.
- 데이터의 선형적인 패턴을 기반으로 하므로, 비선형 데이터에는 잘 맞지 않을 수 있다.
7. PCA를 언제 사용할까?
- 데이터의 차원이 너무 높아서 시각화가 어렵거나, 계산량이 많을 때
- 변수 간 상관성이 높아 중복된 정보가 많을 때
- 머신러닝 모델의 성능을 개선하기 위해 특성 선택(feature selection)이 필요할 때
한 문장 요약
PCA는 데이터의 차원을 줄이면서도 중요한 정보(변동성)를 최대한 유지하는 기법으로,
서로 상관성이 높은 축을 찾아 데이터를 변환(압축)하는 과정이다.
PCA의 단점
1. 해석이 어렵다
- PCA는 원래 변수들의 조합(선형 결합)으로 주성분을 생성한다.
- 따라서 새로운 축(주성분)이 원래 데이터에서 어떤 의미를 가지는지 해석하기 어려울 수 있다.
2. 정보 손실 가능성
- 차원을 줄이면서 일부 변동성이 낮은 데이터는 버려진다.
- 이 과정에서 중요한 정보가 손실될 가능성이 있다.
3. 비선형 데이터에 부적합
- PCA는 데이터의 선형 관계를 기반으로 동작한다.
- 따라서 비선형적인 패턴을 가진 데이터에는 적절하지 않을 수 있다.
4. 스케일링(정규화) 필요
- PCA는 변수들의 분산을 기반으로 하기 때문에 데이터의 크기(scale)가 다르면 제대로 동작하지 않는다.
- 즉, 모든 변수를 같은 기준으로 맞추기 위해 반드시 표준화(Standardization)가 필요하다.
5. 차원 축소 후 원래 데이터 복원이 어려움
- PCA를 사용하여 차원을 줄이면, 원래 데이터로 되돌리기 어렵다.
- 즉, 데이터의 원본 형태를 유지하면서 축소하는 것이 아니라, 변형된 형태로 표현된다.
PCA는 데이터를 축소하는 강력한 도구이지만, 해석이 어렵고, 정보 손실과 비선형 데이터 처리 한계, 정규화 필요성, 원본 복원 어려움 등의 단점이 있다.
PCA의 단점을 보완하는 방법
1. 해석이 어려운 문제 → 주성분의 기여도를 분석
- 해결 방법: 주성분이 원래 변수와 어떤 관계가 있는지 확인하려면, 주성분 로딩(loading) 행렬을 분석하면 된다.
- 실행 코드:
import pandas as pd
pca_loadings = pd.DataFrame(pca.components_, columns=salary_df_numeric.columns)
print(pca_loadings) - 효과: 각 주성분이 원래 변수에 미치는 영향을 파악할 수 있어 해석이 쉬워진다.
2. 정보 손실 문제 → 적절한 주성분 개수 선택
- 해결 방법: 전체 분산의 90~95% 이상을 유지하는 최적의 주성분 개수(n_components)를 선택하면 된다.
- 실행 코드:
import matplotlib.pyplot as plt
import numpy as np
explained_variance_ratio = np.cumsum(pca.explained_variance_ratio_)
plt.plot(range(1, len(explained_variance_ratio) + 1), explained_variance_ratio, marker='o')
plt.xlabel('Number of Principal Components')
plt.ylabel('Cumulative Explained Variance')
plt.show() - 효과: 너무 적은 주성분을 선택하면 정보가 손실되므로, 적절한 개수를 선택해 손실을 최소화할 수 있다.
3. 비선형 데이터 처리 문제 → 커널 PCA(Kernel PCA) 사용
- 해결 방법: 데이터가 비선형 관계를 가질 경우, Kernel PCA를 사용하면 비선형 패턴도 반영할 수 있다.
- 실행 코드:
from sklearn.decomposition import KernelPCA
kpca = KernelPCA(n_components=2, kernel='rbf') # RBF 커널 사용
salary_df_kpca = kpca.fit_transform(salary_df_numeric) - 효과: 선형 PCA보다 더 복잡한 데이터 구조를 학습할 수 있어, 비선형 관계를 반영하는 데 유용하다.
4. 정규화(스케일링) 필요 문제 → PCA 적용 전 데이터 표준화
- 해결 방법: StandardScaler를 사용하여 데이터를 평균 0, 분산 1로 정규화한 후 PCA를 적용하면 스케일 차이 문제를 해결할 수 있다.
- 실행 코드:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
salary_df_scaled = scaler.fit_transform(salary_df_numeric)
pca = PCA(n_components=2)
salary_df_pca = pca.fit_transform(salary_df_scaled) - 효과: 모든 변수의 중요도를 동일하게 만들어, 특정 변수가 과도한 영향을 주는 것을 방지할 수 있다.
5. 차원 축소 후 원본 데이터 복원 문제 → Inverse Transform 사용
- 해결 방법: pca.inverse_transform()을 사용하면, 축소된 데이터를 원래 데이터 공간으로 복원할 수 있다.
- 실행 코드:
salary_df_approx = pca.inverse_transform(salary_df_pca)
- 효과: 원본 데이터를 최대한 유지하면서 차원 축소된 데이터를 활용할 수 있다.
PCA의 단점은 주성분 기여도 분석(해석 문제 해결), 최적 주성분 개수 선택(정보 손실 방지), Kernel PCA(비선형 데이터 대응), 정규화(스케일 문제 해결), Inverse Transform(원본 복원 가능) 등으로 보완할 수 있다.
모델링 하는것도 중요하지만, 해석하는것도 중요하기때문에 PCA로 예측이 올라간다고 해도 해석하기에는 단점이 있으므로 본인의 선택 또는 위에 단점을 보완하는 방법을 사용해야 겠죠.
오류 메시지 AttributeError: 'PCA' object has no attribute 'mean_'는 PCA 객체가 제대로 학습되지 않았을 때 발생하는 오류이다.
즉, pca.fit()을 먼저 수행하지 않고 pca.transform()을 실행했기 때문에 발생한 문제이다.
해결 방법
PCA를 사용하려면 먼저 데이터를 학습(fit)한 후 변환(transform)해야 한다.
1. PCA 학습(fit) 먼저 수행
import numpy as np
# 숫자형 데이터만 선택
salary_df_numeric = salary_df.select_dtypes(include=[np.number])
# PCA 객체 생성 및 학습
pca = PCA(n_components=2) # 예시로 주성분 개수를 2개로 설정
pca.fit(salary_df_numeric) # 데이터를 학습
# 변환 수행
pca_result = pca.transform(salary_df_numeric)
이제 pca.transform()이 정상적으로 실행될 것이다.
2. PCA 객체가 이미 학습되었는지 확인
PCA 객체가 제대로 학습되었는지 확인하려면 pca.mean_ 속성이 존재하는지 확인할 수 있다.
만약 False가 나오면 pca.fit(salary_df_numeric)이 실행되지 않은 상태이므로 반드시 학습을 먼저 수행해야 한다.
오류의 원인은 PCA 객체가 데이터를 학습하지 않은 상태에서 transform을 실행했기 때문이다.
이를 해결하려면 먼저 pca.fit()을 실행한 후 pca.transform()을 수행해야 한다.
변수 중 Data Type이 object인 변수들 제거하고 저장하는 코드는 아래의 두가지경우인데 특징과 장단점
1. salary_df = salary_df.select_dtypes(exclude=['object'])
실행 결과
- 문자형(object) 데이터 타입을 가진 모든 열을 제거.
- 자동으로 모든 문자열 컬럼을 삭제하므로, 특정 컬럼을 지정할 필요 없음.
- 예를 들어, 'Gender', 'Job Title', 'Country', 'Race' 외에도 다른 문자형 변수가 있으면 함께 제거됨.
장점
- 데이터프레임에 있는 모든 문자형 변수를 자동으로 제거하므로 간편함.
- 컬럼 이름을 일일이 지정할 필요 없음.
- 예를 들어, 데이터에 "Department" 같은 새로운 문자형 컬럼이 추가되어도 자동으로 제거됨.
단점
- 숫자형 변수 중에서 문자처럼 저장된 경우(object 타입으로 저장된 숫자)가 있다면 함께 삭제될 수 있음.
- 특정한 문자형 변수만 선택적으로 제거하고 싶을 때는 불필요한 삭제가 발생할 수 있음.
2. salary_df.drop(['Gender','Job Title', 'Country', 'Race'], axis=1, inplace=True)
실행 결과
- 명시적으로 지정한 컬럼만 삭제('Gender', 'Job Title', 'Country', 'Race').
- 이외의 문자형 컬럼은 그대로 유지됨.
장점
- 원하는 컬럼만 정확하게 삭제 가능.
- object 타입이지만 **숫자로 변환할 가능성이 있는 컬럼(예: 'Salary'가 object로 저장된 경우)**은 유지 가능.
- 데이터의 구조를 확실히 알고 있을 때 적절한 방식.
단점
- 새로운 문자형 변수가 추가되면 다시 수동으로 삭제해야 함.
- 특정 문자형 변수를 삭제하고 싶을 때마다 컬럼 리스트를 수정해야 하는 번거로움이 있음.
|
코드별 목적
'데이터 분석가:Applied Data Analytics > 판다스 데이터분석' 카테고리의 다른 글
머신러닝(Machine Learning, ML)-용어편 (0) | 2025.02.14 |
---|---|
4. Data transformation - 영국시장의 중고 자동차 가격 데이터 다루기[프로젝트] (0) | 2025.02.13 |
1. Data cleaning - 타이타닉 데이터 다루기 (0) | 2025.02.11 |
6장_데이터프레임의 다양한 응용(데이터프레임 합치기) (0) | 2025.02.10 |
6장_데이터프레임의 다양한 응용 (1) | 2025.02.10 |