# 4-5.6. 파워쿼리 Titanic 전처리

> 실습 파일

Kaggle의 Titanic Dataset

*Kaggel(캐글)

데이터 과학과 머신러닝 분야 최대의 온라인 플랫폼으로, 전 세계 사용자가 데이터 경진대회에 참가하고, 실제 데이터를 활용해 다양한 분석·예측 모델을 만들고 공유할 수 있는 커뮤니티임.

구글(Google) 산하에서 운영되며, 대회(Competition), 데이터셋, 실습 노트북, 토론 포럼 등 데이터 사이언스 학습과 실력 검증에 필요한 모든 리소스를 무료로 제공함.

[Titanic - Machine Learning from Disaster](https://www.kaggle.com/competitions/titanic/data)

- 라이언 드라이브에서 다운로드 

[https://drive.google.com/file/d/1p0NMUr3GyNyMIYsFQV_n4fOwxPTxuWUA/view?usp=drive_link](https://drive.google.com/file/d/1p0NMUr3GyNyMIYsFQV_n4fOwxPTxuWUA/view?usp=drive_link)

- 데이터 > `테이블 범위에서` 선택 > `표 만들기` 

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/182633_rQcAza9Xskf4meKsXO?q=80&s=1280x180&t=outside&f=webp)

> 파워쿼리를 열면 항상 먼저 해야할 일 두 가지!

1.이름 변경

2.변수 타입 점검

- 이름 변경 : `Titanic_전처리` 

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/183520_SN6xaqV9YveEoNSwhM?q=80&s=1280x180&t=outside&f=webp)

- 변수 타입 점검

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/183544_wgb496UYMrkBtR9qvd?q=80&s=1280x180&t=outside&f=webp)

- 파워쿼리에서 결측치(null) 제거

    - 필터에서 null 체크 해제 (여기서 실습할 내용은 아니니 그냥 '모두 선택')

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/182908_4WSvh8wxNlxuIQlqzG?q=80&s=1280x180&t=outside&f=webp)

## 1.결측치 처리

### 1-1. Embarked 최빈값으로 채우기

- `Embarked` 열 선택

- `홈` > `그룹화` > `확인` 

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/184900_kgIB3M5wPadGkdOxzk?q=80&s=1280x180&t=outside&f=webp)

- `S` 가 554개로 최빈값임을 확인

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/185027_Xp7nsIu247MU9fAdP6?q=80&s=1280x180&t=outside&f=webp)

- 우측 `쿼리설정`  > `적용된 단계` 에서 `그룹화된 행 수` 삭제하고 이전 단계로 이동

- `Embarked` 열 선택 > `변환`  > `값 바꾸기` 

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/185407_YW2t3tX7fUUTyg2bPk?q=80&s=1280x180&t=outside&f=webp)

- 결측치 0% 확인

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/185529_d36I4606j0dTv4zE5y?q=80&s=1280x180&t=outside&f=webp)

---

### 1-2. Age 결측치 채우기

- 성별(Sex)×등급별(Pclass: 객실 등급(1/2/3)) 중앙값 대체

    - 2 x 3 = 총 6개의 중앙값

> 이렇게 결측치를 채우는 것은 하나의 예시임.

상황과 분석 전략에 따라서 케바케. > 모르겠으면 ChatGPT와 대화하기

### 1-2.1 그룹 통계 테이블(중앙값) 만들기

1. **쿼리 복제**: 좌측 쿼리 목록에서 `titanic` 우클릭 → **복제** → 이름을 `age_median`으로 변경.

2. **필요 열만 남기기**: `Sex`, `Pclass`, `Age`만 선택 → 우클릭 **다른 열 제거**.

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/190343_kANvFJRcvW13vgV3Rg?q=80&s=1280x180&t=outside&f=webp)

3. **Null 제거(선택)**: `Age` 열 필터에서 **(null) 해제**.

    1. `1-1` 과정에서 이미 해제했으면 skip.

4. **그룹화**:  `홈` ** → **`그룹화`** > **`고급`** > **`그룹화 추가`** **

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/191058_sa35vGGnD8VsI7Fi2y?q=80&s=1280x180&t=outside&f=webp)

- 결과: 각 `(Sex, Pclass)` 조합마다 `medium_age` 1개 값이 있는 테이블

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/191158_53l7xcCRP7SYv2bwjh?q=80&s=1280x180&t=outside&f=webp)

### 1-2.2 원본에 병합(Join)해서 중앙값 붙이기

1. 좌측 `쿼리` 메뉴 > `Titanic_전처리` 선택

2. 상단 `홈` ** → **`쿼리 병합`** **

- 기본 테이블: `Titanic_전처리`

- 병합 테이블: `age_median`

- 키 선택: 기본에서 `Sex`, `Pclass` 순서로 클릭 → 아래에서도 `Sex`, `Pclass` 클릭(복수선택은 `ctrl` 키를 누르고 열 선택)

- 조인 종류: **왼쪽 외부(Left Outer)**

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/191731_7VaTdVCGsw788BCRMY?q=80&s=1280x180&t=outside&f=webp)

3. 병합 결과 열(테이블 아이콘) 확장 버튼(⤢) 클릭 → `**median_age**`**만 체크** → 확인

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/191912_w38WAykTH69wHqbkCK?q=80&s=1280x180&t=outside&f=webp)

1. `age_new` 열 만들기

- `열 추가`** → **`사용자 지정 열`** **
- 

- 열 이름: `age_new`

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/192312_VyTHy8xaP6bxvdFL2z?q=80&s=1280x180&t=outside&f=webp)

```
if [Age] = null then [Median Age] else [Age]
```

1. `닫기 및 로드`  > `닫기 및 다음으로 로드`  > `새 워크시트` 

![Image](https://upload.cafenono.com/image/slashpageHome/20251108/192810_DgJsq68cnFxWVwqBEl?q=80&s=1280x180&t=outside&f=webp)

1-2.3 정리

- 필요 시 원본 `Age`를 보관하고 `age_new`만 모델 입력에 사용.

- 또는 `Age`를 `age_new`로 **바꾸기**: `Age` 삭제 → `age_new`를 `Age`로 **이름 바꾸기**.

- `age_median` 보조 쿼리는 유지(재실행을 위한 참조)하거나, 최종 배포 전 **로딩 해제**해도 무방.

---

> 파워쿼리로 전처리하는 이유

- 다양한 전처리 기능 지원

- SQL을 그래픽 인터페이스로 제공하는 기

---

---

---

## Google Colab으로 전처리하기

- 전처리할 파일 ChatGPT에 업로드

```
데이터 확인해줘
```

> gpt

데이터를 불러와서 상위 5개 레코드를 확인했어.

컬럼 구성은 다음과 같아:

- **PassengerId**: 승객 번호

- **Survived**: 생존 여부 (0=사망, 1=생존)

- **Pclass**: 객실 등급

- **Name, Sex, Age**: 인적 정보

- **SibSp, Parch**: 동승 가족 수

- **Ticket, Fare, Cabin, Embarked**: 티켓/탑승 관련 정보

추가로 확인하고 싶은 내용이 있어?

예를 들면

**결측치 분포**, **기술 통계**, **컬럼별 분포 시각화**, **상관관계**, **전처리 계획 수립** 등 어떤 방향으로 분석할지 알려주면 계속 도와줄게!

```
전처리해야 할 사항 알려줘
```

> gpt

데이터를 그대로 기준으로 **전처리 관점에서 꼭 확인하거나 수행해야 할 사항**을 정리해줄게.

가능한 부분은 실제 값 기반으로 판단했고, 필요시 _추정임을 명시_했어.

---

# 🔧 Titanic Train Data — 전처리 체크리스트

## 1. **결측치 처리**

데이터를 보면 다음 변수가 결측을 포함하고 있어:

### ● Age

- **결측 존재**

- 일반적으로 생존 분석에서 중요한 변수이므로 반드시 처리 필요

- 처리 방법 예시

    - 중앙값/평균 대체

    - Pclass·Sex 기반 그룹별 중앙값 대체

    - 또는 모델 예측 기반 입력

### ● Cabin

- **대부분 결측**

- 원본 형태를 보아 객실 번호는 매우 희소함

- 처리 방법 예시

    - Cabin 존재 여부만 0/1로 변환 (유용성이 높음)

    - 원본 Cabin 변수는 삭제 고려 가능

### ● Embarked

- **소수 결측**

- 최빈값으로 대체하는 것이 일반적

---

## 2. **범주형 변수 인코딩**

모델링을 위해 다음 변수를 수치화해야 해:

- **Sex** → male/female → 0/1

- **Embarked** → S/C/Q → one-hot 또는 label encoding

- **Cabin 존재 여부** (선택적)

---

## 3. **이상치(outlier) 체크**

특히 다음 변수에서 이상치 점검 필요:

- **Fare**

    - 분포가 한쪽으로 치우쳐 있을 가능성이 높음(일반적인 Titanic 데이터 기준)

- **Age**

    - 음수나 비정상 값은 없음 (표본 일부만 확인했을 때는 정상으로 보임)

---

## 4. **텍스트 변수 처리**

- **Name**

    - 원본은 그대로 사용 가치 낮음

    - 일반적으로 "Mr", "Mrs", "Miss", "Master" 등의 **호칭(Title) 추출**이 유용

- **Ticket**

    - 패턴이 복잡하고 모델 성능 기여도가 낮은 경우가 많음

    - 사용하지 않거나, 접두 문자만 추출해서 사용할 수 있음(선택사항)

---

## 5. **특성 엔지니어링 추천**

Titanic 분석에서는 아래 생성 변수를 자주 사용함:

- **FamilySize = SibSp + Parch + 1**

- **IsAlone = (FamilySize == 1)**

- **Title = Name에서 호칭 추출**

- **CabinExist = Cabin.isnull() 여부**

이 변수들은 생존과 관련된 패턴을 잘 반영하는 경우가 많아.

---

## 6. **스케일링 여부**

- 트리 기반 모델 → 필요 없음

- 로지스틱 회귀, SVM → **Fare** 등 스케일 조정 추천

- Age/Fare의 스케일링 여부는 모델 선택 후 결정하면 됨

---

# 📌 요약: 꼭 해야 하는 전처리

1. Age 결측 대체

2. Cabin → 존재 여부 변수 생성 + 원본 삭제 고려

3. Embarked 결측 → 최빈값 대체

4. Sex / Embarked / CabinExist 인코딩

5. Name에서 Title 추출

6. FamilySize / IsAlone 생성

7. Fare 이상치 확인 및 필요 시 로그 변환

---

필요하면 위 내용을 **코드로 바로 처리해줄 수 있어.**
다음 단계로 "전처리 코드 만들어줘" 또는 "결측치 통계 먼저 보여줘"처럼 알려줘!

```
각각 어떻게 전처리해야 할 지 제안해줘.
```

> gpt

아래는 현재 데이터 구조를 기준으로, **각 변수별로 어떤 전처리를 수행하는 것이 합리적인지**를 단계별로 제안한 내용이야.

가능한 부분은 실제 데이터 값 기반으로 판단했으며, 일부는 Titanic 데이터의 일반 특성에 기반한

_추정_임을 명시한다.

---

# 🔧 변수별 전처리 제안

## 1. **Age**

- 결측 존재 → 반드시 처리 필요

### ✔ 추천 전처리

- **Pclass + Sex 기준 그룹 중앙값으로 대체**
- → 나이 분포가 객실 등급·성별에 따라 달라지는 경향이 명확하기 때문

- 대체 후 분포가 지나치게 뭉개지지 않는지 확인 필요

- 모델링 단계에서 Age가 왜곡된다면,

    - Age_bin = pd.cut(Age, bins=[0, 12, 18, 35, 60, 100]) 같은 구간화도 고려 가능

---

## 2. **Cabin**

- 대부분 결측 → 원본 형태 유지 효과 거의 없음

### ✔ 추천 전처리

- **CabinExist = Cabin.notnull().astype(int)** 생성

- 원본 Cabin 컬럼은 삭제

    - 이유: 문자열 패턴이 복잡하고 희소성이 너무 높음

---

## 3. **Embarked**

- 소수 결측 존재

### ✔ 추천 전처리

- **최빈값(S)**으로 대체

    - Titanic 데이터에서 S가 대부분

    - 실제 파일 기준으로도 S가 우세한 것으로 보이며 합리적임

- 이후 one-hot encoding 적용 (S, C, Q)

---

## 4. **Sex**

- male / female

### ✔ 추천 전처리

- **binary encoding**

    - female → 1, male → 0 (관례적으로 female=1, 생존률 패턴과 직관적)

---

## 5. **Name**

- 텍스트 전체는 불필요하지만, 호칭(Title)은 유용

### ✔ 추천 전처리

- Title = Name.str.extract(r', (.*?).')

- Title rare group 통합

    - Dr, Col, Rev, Countess 등은 빈도가 적기 때문에

    - 'Rare' 그룹으로 합치는 것이 안정적

---

## 6. **SibSp, Parch**

- 단독으로 사용할 수도 있으나, 결합 시 더 높은 예측력

### ✔ 추천 전처리

- FamilySize = SibSp + Parch + 1

- IsAlone = (FamilySize == 1).astype(int)

- 원본 SibSp, Parch는 유지해도 되고 제거해도 됨

    - 일반적으로 유지하는 편

---

## 7. **Fare**

- 이상치 존재 가능성 높음(일반적 패턴)

### ✔ 추천 전처리

- 이상치 확인 후 필요하면 **log1p 변환**

    - Fare_log = np.log1p(Fare)

    - 요금 분포가 심하게 치우쳐 있는 경우 모델 안정성 향상

- 결측은 거의 없으므로 별도 처리 불필요

---

## 8. **Ticket**

- 패턴 다양·중복 많음 → 모델 영향 미미

### ✔ 옵션 제안 (선택)

- 사용하지 않고 삭제

- 또는 "티켓 접두 문자"만 추출하여 활용

    - Ticket.str.replace('^[0-9 ]+', '').str.strip()

    - _효과는 데이터에 따라 달라짐 → 추정_

---

## 9. **Pclass**

- 범주형으로 보이지만 이미 숫자이므로 그대로 사용

### ✔ 추천 전처리

- 별도 인코딩 불필요

- 필요 시 One-hot을 통해 **선형 모델 성능 개선 가능**

---

# 📌 요약 테이블

| 변수 | 권장 전처리 |
| --- | --- |
| Age | Pclass+Sex 그룹 중앙값 대체, 필요 시 binning |
| Cabin | CabinExist 생성 후 원본 삭제 |
| Embarked | 최빈값(S) 대체 → one-hot |
| Sex | female=1, male=0 |
| Name | Title 추출, rare 그룹 병합 |
| SibSp/Parch | FamilySize, IsAlone 생성 |
| Fare | log1p 변환(옵션), 이상치 체크 |
| Ticket | 삭제 또는 접두 문자만 추출 |
| Pclass | 그대로 사용 또는 one-hot |

---

필요하다면

### 👉 "이 전처리를 코드로 만들어줘"

라고 하면 완전한 전처리 코드를 제공할게.

또는 "전처리 수행해서 새로운 CSV로 저장해줘"도 가능해!

```
첨부파일의 데이터를 colab을 통해서 전처리하고 싶어.
업로드 > 전처리 > 다운로드까지 진행하는 파이썬 코드 만들어줘.
```

> gpt

Colab에 그대로 붙여서 **위에서부터 순서대로 실행**하면 되는 코드야.

(업로드 → 전처리 → 다운로드)

---

## 1️⃣ CSV 업로드 셀

```
from google.colab import files
import io
import pandas as pd
import numpy as np

# 1. 파일 업로드
uploaded = files.upload()  # CSV 선택

# 업로드한 파일 이름 (첫 번째 파일 기준)
filename = list(uploaded.keys())[0]
print("Uploaded file:", filename)

# CSV 로드
df = pd.read_csv(io.BytesIO(uploaded[filename]))
print("Raw shape:", df.shape)
df.head()
```

---

## 2️⃣ 전처리 셀

```
# ===== 2. Preprocessing v2 =====

df_raw = df.copy()  # 원본 보존

# 2-1. Embarked 결측치 → 최빈값으로 대체
if df['Embarked'].isnull().sum() > 0:
    most_freq_embarked = df['Embarked'].mode()[0]
    df['Embarked'] = df['Embarked'].fillna(most_freq_embarked)

# 2-2. CabinExist 생성 후 Cabin 컬럼 삭제
df['CabinExist'] = df['Cabin'].notnull().astype(int)
df = df.drop(columns=['Cabin'])

# 2-3. Name에서 Title 추출
df['Title'] = df['Name'].str.extract(r',\s*([^\.]+)\.', expand=False)
df['Title'] = df['Title'].str.strip()  # 공백 제거

# 대표 타이틀만 남기고 나머지는 Rare로 통합
common_titles = ['Mr', 'Mrs', 'Miss', 'Master']
df['Title'] = df['Title'].apply(lambda x: x if x in common_titles else 'Rare')

# 2-4. FamilySize, IsAlone 생성
df['FamilySize'] = df['SibSp'] + df['Parch'] + 1
df['IsAlone'] = (df['FamilySize'] == 1).astype(int)

# 2-5. Age 결측치: Pclass + Sex(문자) 그룹 중앙값으로 대체
age_median_by_group = df.groupby(['Pclass', 'Sex'])['Age'].median()

def fill_age(row):
    if pd.isnull(row['Age']):
        return age_median_by_group.loc[row['Pclass'], row['Sex']]
    return row['Age']

df['Age'] = df.apply(fill_age, axis=1)

# 2-6. Sex를 binary 인코딩 (female=1, male=0)
df['Sex'] = df['Sex'].map({'female': 1, 'male': 0})

# 2-7. Fare 로그 변환 (분포 완화용)
df['Fare_log'] = np.log1p(df['Fare'])

# 2-8. Embarked, Title 원-핫 인코딩 (0/1 타입으로 명시)
df = pd.get_dummies(df,
                    columns=['Embarked', 'Title'],
                    drop_first=True,
                    dtype=int)

# 2-9. 분석에 잘 안 쓰이는 Ticket, Name 삭제
drop_cols = []
for col in ['Ticket', 'Name']:
    if col in df.columns:
        drop_cols.append(col)
if drop_cols:
    df = df.drop(columns=drop_cols)

print("Preprocessed shape:", df.shape)
df.head()
```

---

## 3️⃣ 전처리 결과 다운로드 셀

```
# ===== 3. Save & Download =====

output_filename = 'titanic_train_preprocessed_v2.csv'  # 영어, 언더스코어, v2

df.to_csv(output_filename, index=False)
files.download(output_filename)
```

---

- Colab에서 1번 코드를 ctrl+v 하고 > shift+enter

- 파일 선택 > 업로드

- 2번 코드 ctrl+v 하고 > shift+enter

- 3번 코드 ctrl+v 하고 > shift+enter

- 전처리된 tidy data 다운로드 > 확인하기

For the site tree, see the [root Markdown](https://slashpage.com/lion.md).
