6. 데이터 다루기#
기본 설정
pandas 라이브러리를 pd라는 이름으로 불러온다
import pandas as pd
데이터프레임의 chained indexing을 금지시키기 위한 설정을 지정한다. Pandas 3.0 버전부터는 기본 옵션으로 지정된다.
pd.options.mode.copy_on_write = True
데이터 저장소 디렉토리
앞으로 사용할 데이터셋들의 기본 저장소를 지정한다.
data_url = 'https://raw.githubusercontent.com/codingalzi/statsRev/refs/heads/master/data/'
6.1. 데이터셋 불러오기#
위 url의 ‘ch01_sport_test.csv’ 파일은 아래 그림처럼 학생 10명의 체력 테스트 결과가 쉼표로 구분해 저장한 것이다. 이런 식으로 엑셀 형식으로 표현되는 데이터를 태뷸러 데이터tabular data라 한다.

아래 코드는 Pandas의 read_csv() 함수를 이용해 위 태블렛 데이터를 읽어온다. 학생번호를 인덱스로 지정하고,
생성된 데이터프레임을 변수 sports_df에 할당한다. 출력된 결과를 보면 학생번호가 인덱스로 지정된 것을 알 수 있다.
sports_df = pd.read_csv(data_url+'ch01_sport_test.csv', index_col='학생번호')
sports_df
| 학년 | 악력 | 윗몸일으키기 | 점수 | 순위 | |
|---|---|---|---|---|---|
| 학생번호 | |||||
| 1 | 1 | 40.2 | 34 | 15 | 4 |
| 2 | 1 | 34.2 | 14 | 7 | 10 |
| 3 | 1 | 28.8 | 27 | 11 | 7 |
| 4 | 2 | 39.0 | 27 | 14 | 5 |
| 5 | 2 | 50.9 | 32 | 17 | 2 |
| 6 | 2 | 36.5 | 20 | 9 | 9 |
| 7 | 3 | 36.6 | 31 | 13 | 6 |
| 8 | 3 | 49.2 | 37 | 18 | 1 |
| 9 | 3 | 26.0 | 28 | 10 | 8 |
| 10 | 3 | 47.4 | 32 | 16 | 3 |
6.2. 데이터프레임 기초 정보#
데이터프레임이 제공하는 기능을 이용하여 저장된 데이터셋의 다양한 정보를 확인할 수 있다.
모양 정보
모양 정보는 shape 속성으로 확인할 수 있다. 출력된 튜플의 첫째 항목은 데이터셋에 포함된 샘플의 개수를, 둘째 항목은 각 샘플에 포함된 특성의 개수를 의미한다. 데이터프레임 sports_df는 총 10개의 데이터 샘플이 5개의 특성들로 표현되어 있음이 확인된다.
sports_df.shape
(10, 5)
특성의 종류
데이터 샘플의 특성 종류는 columns 속성과 info() 함수를 통해 확인할 수 있다.
sports_df.columns
Index(['학년', '악력', '윗몸일으키기', '점수', '순위'], dtype='object')
sports_df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 10 entries, 1 to 10
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 학년 10 non-null int64
1 악력 10 non-null float64
2 윗몸일으키기 10 non-null int64
3 점수 10 non-null int64
4 순위 10 non-null int64
dtypes: float64(1), int64(4)
memory usage: 480.0 bytes
특성은 수치형 특성과 범주형 특성으로 나뉘고, 수치형 특성은 이산형과 연속형으로 나눌 수 있다. 위 데이터의 경우, 학년은 범주형 특성, 나머지는 모두 수치형 특성인데, 악력을 제외한 수치형 특성들은 모두 이산형임을 알 수 있다.
데이터셋의 수치형 특성의 기본 통계 정보
sports_df.describe()
| 학년 | 악력 | 윗몸일으키기 | 점수 | 순위 | |
|---|---|---|---|---|---|
| count | 10.000000 | 10.000000 | 10.000000 | 10.000000 | 10.00000 |
| mean | 2.100000 | 38.880000 | 28.200000 | 13.000000 | 5.50000 |
| std | 0.875595 | 8.337306 | 6.828047 | 3.651484 | 3.02765 |
| min | 1.000000 | 26.000000 | 14.000000 | 7.000000 | 1.00000 |
| 25% | 1.250000 | 34.775000 | 27.000000 | 10.250000 | 3.25000 |
| 50% | 2.000000 | 37.800000 | 29.500000 | 13.500000 | 5.50000 |
| 75% | 3.000000 | 45.600000 | 32.000000 | 15.750000 | 7.75000 |
| max | 3.000000 | 50.900000 | 37.000000 | 18.000000 | 10.00000 |
6.3. 인덱싱#
여기서는 불러들인 데이터셋을 이용해 앞에서 배운 행과 열 인덱싱을 간단하게 복습하기로 하자.
6.3.1. 행 인덱싱#
loc메서드
데이터프레임 sports_df를 생성할 때, 학생번호를 인덱스로 지정했던 것을 기억할 것이다. 따라서 loc 메서드를 이용하면 학생번호가 1인 학생의 체력 테스트 결과를 별도의 시리즈로 추출할 수 있다.
sports_df.loc[1]
학년 1.0
악력 40.2
윗몸일으키기 34.0
점수 15.0
순위 4.0
Name: 1, dtype: float64
iloc메서드
반면에, iloc 메서드를 사용하면 각 행에 자동으로 매겨진 정수 인덱스를 이용해 학생번호가 1인 학생의 정보를 동일하게 얻을 수 있다.
sports_df.iloc[0]
학년 1.0
악력 40.2
윗몸일으키기 34.0
점수 15.0
순위 4.0
Name: 1, dtype: float64
6.3.2. 열 인덱싱#
데이터프레임에서 악력에 대한 열을 추출하면 모든 학생의 악력에 대한 정보만을 담은 1차원 자료구조인 시리즈Series가 반환된다.
악력1D = sports_df['악력']
악력1D
학생번호
1 40.2
2 34.2
3 28.8
4 39.0
5 50.9
6 36.5
7 36.6
8 49.2
9 26.0
10 47.4
Name: 악력, dtype: float64
악력1D.ndim
1
반면에 아래와 같이 리스트를 사용하면 2차원 자료구조인 데이터프레임이 반환된다.
악력2D = sports_df[['악력']]
악력2D
| 악력 | |
|---|---|
| 학생번호 | |
| 1 | 40.2 |
| 2 | 34.2 |
| 3 | 28.8 |
| 4 | 39.0 |
| 5 | 50.9 |
| 6 | 36.5 |
| 7 | 36.6 |
| 8 | 49.2 |
| 9 | 26.0 |
| 10 | 47.4 |
악력2D.ndim
2
악력1D와 악력2D는 내용면에서는 동일하며 거의 동일하게 활용될 수 있다.
하지만 여러 개의 특성을 지정하려면 반드시 리스트 형식으로 사용해야 한다.
예를 들어 아래 코드는 모든 학생에 대해 학년과 악력 정보를 함께 담은 데이터프레임을 가리킨다.
학년과악력 = sports_df[['학년', '악력']]
학년과악력
| 학년 | 악력 | |
|---|---|---|
| 학생번호 | ||
| 1 | 1 | 40.2 |
| 2 | 1 | 34.2 |
| 3 | 1 | 28.8 |
| 4 | 2 | 39.0 |
| 5 | 2 | 50.9 |
| 6 | 2 | 36.5 |
| 7 | 3 | 36.6 |
| 8 | 3 | 49.2 |
| 9 | 3 | 26.0 |
| 10 | 3 | 47.4 |
loc과 iloc 메서드를 이용해 열 인덱싱을 할 수도 있는데, 이때는 행 전체를 나타내는 :이 동반되어야 한다.
loc 활용
악력1D = sports_df.loc[:, '악력']
악력1D
학생번호
1 40.2
2 34.2
3 28.8
4 39.0
5 50.9
6 36.5
7 36.6
8 49.2
9 26.0
10 47.4
Name: 악력, dtype: float64
악력2D = sports_df.loc[:, ['악력']]
악력2D
| 악력 | |
|---|---|
| 학생번호 | |
| 1 | 40.2 |
| 2 | 34.2 |
| 3 | 28.8 |
| 4 | 39.0 |
| 5 | 50.9 |
| 6 | 36.5 |
| 7 | 36.6 |
| 8 | 49.2 |
| 9 | 26.0 |
| 10 | 47.4 |
학년과약력 = sports_df.loc[:, ['학년', '악력']]
학년과약력
| 학년 | 악력 | |
|---|---|---|
| 학생번호 | ||
| 1 | 1 | 40.2 |
| 2 | 1 | 34.2 |
| 3 | 1 | 28.8 |
| 4 | 2 | 39.0 |
| 5 | 2 | 50.9 |
| 6 | 2 | 36.5 |
| 7 | 3 | 36.6 |
| 8 | 3 | 49.2 |
| 9 | 3 | 26.0 |
| 10 | 3 | 47.4 |
iloc 활용
자동으로 부여된 열 인덱스인 0, 1, 2, ..를 사용하면 된다.
악력1D = sports_df.iloc[:, 1]
악력1D
학생번호
1 40.2
2 34.2
3 28.8
4 39.0
5 50.9
6 36.5
7 36.6
8 49.2
9 26.0
10 47.4
Name: 악력, dtype: float64
악력2D = sports_df.iloc[:, 1:2]
악력2D
| 악력 | |
|---|---|
| 학생번호 | |
| 1 | 40.2 |
| 2 | 34.2 |
| 3 | 28.8 |
| 4 | 39.0 |
| 5 | 50.9 |
| 6 | 36.5 |
| 7 | 36.6 |
| 8 | 49.2 |
| 9 | 26.0 |
| 10 | 47.4 |
학년과약력 = sports_df.iloc[:, :2]
학년과약력
| 학년 | 악력 | |
|---|---|---|
| 학생번호 | ||
| 1 | 1 | 40.2 |
| 2 | 1 | 34.2 |
| 3 | 1 | 28.8 |
| 4 | 2 | 39.0 |
| 5 | 2 | 50.9 |
| 6 | 2 | 36.5 |
| 7 | 3 | 36.6 |
| 8 | 3 | 49.2 |
| 9 | 3 | 26.0 |
| 10 | 3 | 47.4 |
6.4. 연습문제#
참고: (연습) 데이터 다루기