데이터 분석의 핵심, DataFrame 완벽 가이드
1. DataFrame 개요
Pandas의 DataFrame은 2차원 테이블 형태의 데이터 구조입니다.
Excel의 Spreadsheet이나 SQL의 Table과 매우 유사하며, 데이터 분석 및 머신러닝에서 가장 많이 활용됩니다.
2차원이기 때문에 인덱스가 row, column로 구성됩니다.
row는 각 개별 데이터를, column은 개별 속성을 의미합니다. ('feature' 라고도 함)
- Series: 1차원 배열 (Column 하나)
- DataFrame: 2차원 배열 (Series의 집합)
- Index: 행(Row)을 식별하는 고유 값
- Column/Feature: 열(속성), 데이터의 특성을 의미
2. 환경 설정 및 데이터 로드
라이브러리 임포트
import numpy as np
import pandas as pd
import os
데이터 불러오기 (Google Colab & CSV)
from google.colab import drive
drive.mount('/content/drive')
base_path = r'/content/drive/MyDrive/dataset'
filepath = os.path.join(base_path, 'titanic.csv')
df = pd.read_csv(filepath)
출력 결과
| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 0 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
| 1 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
| 2 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S |
| 3 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S |
| 4 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 886 | 0 | 2 | Montvila, Rev. Juozas | male | 27.0 | 0 | 0 | 211536 | 13.0000 | NaN | S |
| 887 | 1 | 1 | Graham, Miss. Margaret Edith | female | 19.0 | 0 | 0 | 112053 | 30.0000 | B42 | S |
| 888 | 0 | 3 | Johnston, Miss. Catherine Helen "Carrie" | female | NaN | 1 | 2 | W./C. 6607 | 23.4500 | NaN | S |
| 889 | 1 | 1 | Behr, Mr. Karl Howell | male | 26.0 | 0 | 0 | 111369 | 30.0000 | C148 | C |
| 890 | 0 | 3 | Dooley, Mr. Patrick | male | 32.0 | 0 | 0 | 370376 | 7.7500 | NaN | Q |
[891 rows x 12 columns]
컬럼 의미
3. 데이터 파악 (EDA 기초)
데이터 미리보기
df.head() # 상위 5개 행 출력 (기본값 5)
df.tail(7) # 하위 7개 행 출력
데이터 정보 및 통계 확인
# 1. shape: (행, 열) 크기 확인
print(df.shape) #(891,12)
# 2. info(): 컬럼 타입, 결측치(Non-null) 개수 확인
df.info()
#출력 결과
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
# 3. describe(): 숫자형 데이터의 기술통계량 출력
# 숫자형 데이터에 대해 기술통계량 정보
# count, mean, std : 개수, 평균, 표준편차
# max, min : 최대, 최소
# 25%, 50%, 75% : 하위 4분위 하위 2분위...
df.describe()
4. DataFrame 생성 및 속성
리스트(List)로 생성
df_list = pd.DataFrame([
[1, 2, 3],
[4, 5, 6]
], columns=['A', 'B', 'C'], index=['Row1', 'Row2'])
딕셔너리(Dict)로 생성
index= 없어도 생성됨! (기본 0-base index)
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35],
'City': ['Seoul', 'Busan', 'Incheon']
}
df_dict = pd.DataFrame(data)
| Name | Age | City |
|---|
| 0 | Alice | 25 | Seoul |
| 1 | Bob | 30 | Busan |
| 2 | Charlie | 35 | Incheon |
주요 속성들
df.index
df.columns
df.dtypes
df.size
df.ndim
5. 인덱스 및 컬럼 조작
이름 변경 (Rename)
df2 = pd.DataFrame([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
], columns = ['국어', '영어', '수학', '과학']
df2.index = ['고길동', '둘리', '마이콜']
| 국어 | 영어 | 수학 | 과학 |
|---|
| 고길동 | 1 | 2 | 3 | 4 |
| 둘리 | 5 | 6 | 7 | 8 |
| 마이콜 | 9 | 10 | 11 | 12 |
df2.rename(columns={'국어':'kor', "과학":'Sci'})
인덱스 재설정 (Reset & Set)
df2.reset_index(inplace=True)
| index | 국어 | 영어 | 수학 | 과학 |
|---|
| 0 | 고길동 | 1 | 2 | 3 | 4 |
| 1 | 둘리 | 5 | 6 | 7 | 8 |
| 2 | 마이콜 | 9 | 10 | 11 | 12 |
df2.reset_index(drop=True)
| 국어 | 영어 | 수학 | 과학 |
|---|
| 0 | 1 | 2 | 3 | 4 |
| 1 | 5 | 6 | 7 | 8 |
| 2 | 9 | 10 | 11 | 12 |
df2.set_index('국어')
| 국어 |
|
| 영어 |
수학 |
과학 |
| 1 |
2 |
3 |
4 |
| 5 |
6 |
7 |
8 |
| 9 |
10 |
11 |
12 |
퀴즈: 인덱스와 컬럼 스와이프
원본(df2)
| index | 국어 | 영어 | 수학 | 과학 |
|---|
| 0 | 고길동 | 1 | 2 | 3 | 4 |
| 1 | 둘리 | 5 | 6 | 7 | 8 |
| 2 | 마이콜 | 9 | 10 | 11 | 12 |
df2.reset_index().set_index('국어')
| 국어 (index) | index | 영어 | 수학 | 과학 |
|---|
| 1 | 고길동 | 2 | 3 | 4 |
| 5 | 둘리 | 6 | 7 | 8 |
| 9 | 마이콜 | 10 | 11 | 12 |
6. 멀티 인덱스 (Multi-level Index)
복잡한 구조의 데이터를 표현할 때 사용합니다.
pd.DataFrame({('k0', 'k1'): [10]})
pd.DataFrame({('k0', 'k1'): {('a1', 'a2'): 10, ('b1', 'b2'): 40}})
df4 = pd.DataFrame(
{
('k', 'k1') : [10, 20, 30, 31],
('k', 'k2') : [40, 50, 60, 61],
('j', 'j1') : [70, 80, 90, 91],
('j', 'j2') : [100, 110, 120, 121],
},
index = [['서울', '서울', '경기', '경기'], ['평일', '휴일', '평일', '휴일']]
)
|
|
k |
j |
|
|
k1 |
k2 |
j1 |
j2 |
| 서울 |
평일 |
10 |
40 |
70 |
100 |
| 휴일 |
20 |
50 |
80 |
110 |
| 경기 |
평일 |
30 |
60 |
90 |
120 |
| 휴일 |
31 |
61 |
91 |
121 |
데이터프레임 선택 및 필터링
Pandas의 DataFrame에서 특정 컬럼, 로우(행), 그리고 조건에 맞는 데이터를 선택하는 방법들을 정리합니다.
1. 하나의 컬럼 선택
컬럼명을 직접 지정하거나 속성(Attribute) 방식을 사용할 수 있습니다.
2. 복수의 컬럼 선택하기
리스트 형태로 컬럼명을 전달하면 DataFrame 형태로 반환됩니다.
-
df[['Survived']]: 대괄호를 두 번 쓰면 결과는 DataFrame이다.
-
df[['Survived', 'Age', 'Name']]: 여러 컬럼을 한꺼번에 선택 가능하며, 순서 변경이나 중복 선택도 가능하다.
3. Row(행) 선택하기: loc[], iloc[]
DataFrame은 기본적으로 []를 컬럼 선택에 사용하므로, 행 선택을 위해서는 전용 속성이 필요합니다.
예제
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 986 | 887 | 0 | 2 | Montvila, Rev. Juozas | male | 27.0 | 0 | 0 | 211536 | 13.00 | NaN | S |
| 987 | 888 | 1 | 1 | Graham, Miss. Margaret Edith | female | 19.0 | 0 | 0 | 112053 | 30.00 | B42 | S |
| 988 | 889 | 0 | 3 | Johnston, Miss. Catherine Helen "Carrie" | female | NaN | 1 | 2 | W./C. 6607 | 23.45 | NaN | S |
| 989 | 890 | 1 | 1 | Behr, Mr. Karl Howell | male | 26.0 | 0 | 0 | 111369 | 30.00 | C148 | C |
| 990 | 891 | 0 | 3 | Dooley, Mr. Patrick | male | 32.0 | 0 | 0 | 370376 | 7.75 | NaN | Q |
3.1 loc (Label-based)
인덱스 자체(이름)를 사용하여 선택합니다.
df.loc[986]: 해당 인덱스의 데이터를 Series로 반환
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 986 | 887 | 0 | 2 | Montvila, Rev. Juozas | male | 27.0 | 0 | 0 | 211536 | 13.0 | NaN | S |
df.loc[[986]]: 해당 인덱스의 데이터를 DataFrame으로 반환
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 986 | 887 | 0 | 2 | Montvila, Rev. Juozas | male | 27.0 | 0 | 0 | 211536 | 13.0 | NaN | S |
* `df.loc[[986, 100, 110]]`: 여러 인덱스 동시 선택
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 986 | 887 | 0 | 2 | Montvila, Rev. Juozas | male | 27.0 | 0 | 0 | 211536 | 13.00 | NaN | S |
| 100 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.25 | NaN | S |
| 110 | 11 | 1 | 3 | Sandstrom, Miss. Marguerite | female | 4.0 | 1 | 1 | PP 9549 | 16.70 | G6 | S |
| 990 | 891 | 0 | 3 | Dooley, Mr. Patrick | male | 32.0 | 0 | 0 | 370376 | 7.75 | NaN | Q |
3.2 iloc (Integer-based)
0부터 시작하는 순서(Position)를 기준으로 선택합니다. (0 based index)
df.iloc[0]: 0번 인덱스가 아니라, '첫 번째' 행을 의미 (Series)
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 100 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.25 | NaN | S |
df.iloc[[0, 100, 200, 2]]: 0, 100, 200, 2번째 행을 DataFrame으로 반환
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 100 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
| 200 | 101 | 0 | 3 | Petranec, Miss. Matilda | female | 28.0 | 0 | 0 | 349245 | 7.8958 | NaN | S |
| 300 | 201 | 0 | 3 | Vande Walle, Mr. Nestor Cyriel | male | 28.0 | 0 | 0 | 345770 | 9.5000 | NaN | S |
| 102 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S |
4. Row와 Column 동시에 선택하기
loc와 iloc에 콤마(,)를 사용하여 행과 열을 동시에 지정할 수 있습니다.
예제
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 986 | 887 | 0 | 2 | Montvila, Rev. Juozas | male | 27.0 | 0 | 0 | 211536 | 13.00 | NaN | S |
| 987 | 888 | 1 | 1 | Graham, Miss. Margaret Edith | female | 19.0 | 0 | 0 | 112053 | 30.00 | B42 | S |
| 988 | 889 | 0 | 3 | Johnston, Miss. Catherine Helen "Carrie" | female | NaN | 1 | 2 | W./C. 6607 | 23.45 | NaN | S |
| 989 | 890 | 1 | 1 | Behr, Mr. Karl Howell | male | 26.0 | 0 | 0 | 111369 | 30.00 | C148 | C |
| 990 | 891 | 0 | 3 | Dooley, Mr. Patrick | male | 32.0 | 0 | 0 | 370376 | 7.75 | NaN | Q |
`df.loc[986, 'Survived']`: 특정 인덱스의 특정 컬럼 값 선택
np.int64(0)
df.iloc[-5, -3]
np.float64(13.0)
예제2
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
|---|
| 100 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
| 101 | 2 | 1 | 1 | Cumings, Mrs. John Bradley | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
| 102 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S |
| 103 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S |
| 104 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S |
df.loc[102, 'Name']
Heikkinen, Miss. Laina
df.iloc[2, 3]
Heikkinen, Miss. Laina
df.loc[[986, 100, 110, 990], ['Survived', 'Name', 'Sex', 'Age']]
| Index | Survived | Name | Sex | Age |
|---|
| 986 | 0 | Montvila, Rev. Juozas | male | 27.0 |
| 100 | 0 | Braund, Mr. Owen Harris | male | 22.0 |
| 110 | 1 | Sandstrom, Miss. Marguerite Rut | female | 4.0 |
| 990 | 0 | Dooley, Mr. Patrick | male | 32.0 |
참고: 체이닝(Chaining) 방식
df['Name'][102] 또는 df.loc[102]['Name'] 처럼 연속해서 인덱싱하는 것도 가능하지만,
가급적 loc[row, col] 방식을 권장합니다.
5. Boolean Selection으로 Row 선택하기
조건문(Mask)을 이용하여 특정 조건에 맞는 데이터만 추출합니다.
5.1 데이터 탐색 (Value Check)
Pclass는 객실의 등급입니다.
df.Pclass.unique(): 클래스의 종류 확인 (1, 2, 3)
df.Pclass.value_counts(): 클래스별 데이터 개수 확인
| Pclass | Count |
|---|
| 3등급 (3) | 491명 |
| 1등급 (1) | 216명 |
| 2등급 (2) | 184명 |
5.2 조건 필터링 (Masking)
조건을 변수에 담아 가독성을 높일 수 있습니다.
pclass_mask = df['Pclass'] == 1
df[pclass_mask]
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | Fare | Cabin | Embarked |
|---|
| 101 | 2 | 1 | 1 | Cumings, Mrs. John Bradley | female | 38.0 | 71.2833 | C85 | C |
| 103 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath | female | 35.0 | 53.1000 | C123 | S |
| 106 | 7 | 0 | 1 | McCarthy, Mr. Timothy J | male | 54.0 | 51.8625 | E46 | S |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 989 | 890 | 1 | 1 | Behr, Mr. Karl Howell | male | 26.0 | 30.0000 | C148 | C |
age_mask = (df.Age >= 30) & (df.Age < 40)
df[age_mask]
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | Fare | Cabin | Embarked |
|---|
| 101 | 2 | 1 | 1 | Cumings, Mrs. John Bradley | female | 38.0 | 71.2833 | C85 | C |
| 103 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath | female | 35.0 | 53.1000 | C123 | S |
| 104 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 8.0500 | NaN | S |
| 113 | 14 | 0 | 3 | Andersson, Mr. Anders Johan | male | 39.0 | 31.2750 | NaN | S |
| 118 | 19 | 0 | 3 | Vander Planke, Mrs. Julius | female | 31.0 | 18.0000 | NaN | S |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 967 | 868 | 0 | 1 | Roebling, Mr. Washington Augustus II | male | 31.0 | 50.4958 | A24 | S |
| 972 | 873 | 0 | 1 | Carlsson, Mr. Frans Olof | male | 33.0 | 5.0000 | B51 B53 | S |
| 981 | 882 | 0 | 3 | Markun, Mr. Johann | male | 33.0 | 7.8958 | NaN | S |
| 985 | 886 | 0 | 3 | Rice, Mrs. William (Margaret Norton) | female | 39.0 | 29.1250 | NaN | Q |
| 990 | 891 | 0 | 3 | Dooley, Mr. Patrick | male | 32.0 | 7.7500 | NaN | Q |
df[pclass_mask & age_mask]
| Index | PassengerId | Survived | Pclass | Name | Sex | Age | Fare | Cabin | Embarked |
|---|
| 101 | 2 | 1 | 1 | Cumings, Mrs. John Bradley | female | 38.0 | 71.2833 | C85 | C |
| 103 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath | female | 35.0 | 53.1000 | C123 | S |
| 161 | 62 | 1 | 1 | Icard, Miss. Amelie | female | 38.0 | 80.0000 | B28 | NaN |
| 237 | 138 | 0 | 1 | Futrelle, Mr. Jacques Heath | male | 37.0 | 53.1000 | C123 | S |
| 315 | 216 | 1 | 1 | Newell, Miss. Madeleine | female | 31.0 | 113.2750 | D36 | C |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 779 | 680 | 1 | 1 | Cardeza, Mr. Thomas Drake Martinez | male | 36.0 | 512.3292 | B51 B53 | C |
| 906 | 807 | 0 | 1 | Andrews, Mr. Thomas Jr | male | 39.0 | 0.0000 | A36 | S |
| 967 | 868 | 0 | 1 | Roebling, Mr. Washington Augustus II | male | 31.0 | 50.4958 | A24 | S |
| 972 | 873 | 0 | 1 | Carlsson, Mr. Frans Olof | male | 33.0 | 5.0000 | B51 B53 | S |
df[pclass_mask & age_mask][['Pclass', 'Age']]
| Index | Pclass | Age |
|---|
| 101 | 1 | 38.0 |
| 103 | 1 | 35.0 |
| 161 | 1 | 38.0 |
| 237 | 1 | 37.0 |
| 315 | 1 | 31.0 |
| ... | ... | ... |
| 935 | 1 | 39.0 |
| 942 | 1 | 30.0 |
| 967 | 1 | 31.0 |
| 972 | 1 | 33.0 |
퀴즈
3등급 객실의 생존자 수는?
pclass_mask = df['Pclass'] == 3
Survived_mask = df['Survived'] == 1
len(df[pclass_mask & Survived_mask])