2.1. 데이터프레임의 정의 및 행과 열선택#
실제 데이터를 다루기 전에 데이터프레임은 무엇인지 짚고 넘어갈 필요가 있습니다.
import pandas as pd
정의#
이제 데이터프레임을 정의해 보자. 다음은 5명의 이름, 성별, 나이, 키가 저장된 데이터프레임을 직접 만드는 코드이다.
df = pd.DataFrame(
{ 'name' : ['이철수', '김영희', '홍길동', 'John Smith', 'Mary Doe'],
'gender' : ['M', 'F', 'M', 'M', 'F'],
'age' : [ 23, 25, 21, 33, 45],
'height' : [153.5, 175.3, 163.4, 180.0, 165.7]
} )
df
| name | gender | age | height | |
|---|---|---|---|---|
| 0 | 이철수 | M | 23 | 153.5 |
| 1 | 김영희 | F | 25 | 175.3 |
| 2 | 홍길동 | M | 21 | 163.4 |
| 3 | John Smith | M | 33 | 180.0 |
| 4 | Mary Doe | F | 45 | 165.7 |
type(df)
pandas.core.frame.DataFrame
각 행을 나타내는 인덱스는 0으로 시작하는 정수 0,1,2,3,4 로 나타나고 각 열을 나타내는 인덱스(열이름)는 문자열로 나타나며
name,gender,age,height로 나타난다.
위의 코드는 5명의 학생의 이름(name), 성별(gender), 나이(age), 키(height)로 구성된 5개의 행과 4개 열을 가진 데이터프레임 df 이다. pd.DataFrame() 는 pd 로 지정된 pandas 라이브러리의 함수 DataFrame() 을 사용하겠다는 의미이다. 라이브러리의 함수 DataFrame의 괄호 안에 인자는 괄호 { 로 시작하여 괄호 } 로 끝나는 표현식이 들어 간다.
괄호 {} 안에 있는 표현식은 사전(dictionary) 형식의 데이터를 만들어 준다.
괄호
{}안에 있는 첫 번째 요소는 이름을 나타내는 열을 만드는 표현식이며 열이름은name이고 원소들은 문자열(str)로 구성된 리스트이다.
'name' : ['이철수', '김영희', '홍길동', 'John Smith', 'Mary Doe']
괄호
{}안에 있는 두 번째 요소는 성별을 나타내는 열을 만드는 표현식이며 열이름은gender이고 원소들은 문자열M과F로 구성된 리스트이다.
'gender' : ['M', 'F', 'M', 'M', 'F']
괄호
{}안에 있는 세 번째 요소는 나이을 나타내는 열을 만드는 표현식이며 열이름은age이고 원소들은 정수(int)로 구성된 리스트이다.
'age' : [ 23, 25, 21, 33, 45]
괄호
{}안에 있는 네 번째 요소는 키를 나타내는 열을 만드는 표현식이며 열이름은height이고 원소들은 부동소수점(float)로 구성된 리스트이다.
'height' : [153.5, 175.3, 163.4, 180.0, 165.7]
각 열을 나타내는 4개의 요소는 쉼표 , 로 분리한다.
열(column) 선택#
데이터프레임에서 다음과 같이 괄호 [] 안에 열이름 또는 열이름으로 구성된 리스트를 넣어서 일부의 열을 선택할 수 있다. 이 경우 열이름은 문자열이어야 한다.
데이터프레임에서 열 또는 행의 일부를 선택하여 추출하는 작업을 슬라이싱(slicing) 이라고 한다.
df['name']
0 이철수
1 김영희
2 홍길동
3 John Smith
4 Mary Doe
Name: name, dtype: object
df[['age', 'height']]
| age | height | |
|---|---|---|
| 0 | 23 | 153.5 |
| 1 | 25 | 175.3 |
| 2 | 21 | 163.4 |
| 3 | 33 | 180.0 |
| 4 | 45 | 165.7 |
하나의 열만 슬라이싱하는 경우는 데이터프레임 이름 뒤에 마침표를 붙이고 열이름을 붙이면 된다.
df.age
0 23
1 25
2 21
3 33
4 45
Name: age, dtype: int64
행(row) 선택#
이제 특정한 성질을 가진 행, 즉 자료의 구성 단위의 일부만을 선택해 보자. 데이터프레임 뒤 괄호 [] 안에 비교연산자를 이용한 조건 표현식을 넣어주면 조건이 만족하는 행만 추출된다.
성별이 남자인 사람만 추출해보자.
데이터프레임에 5명의 사람의 정보가 행으로 들어가 있으니 각 사람마다 남자인지 아닌지 판단을 해야 하는 조건 표현식이 필요합니다.
위에서 언급한 조건 표현식은 df['gender'] == 'M' 로서 df['gender'] 의 자료를 각각 문자열 M 과 비교하여 참이면 True, 거짓이면 False 로 결과를 생성한다.
df['gender'] == 'M'
0 True
1 False
2 True
3 True
4 False
Name: gender, dtype: bool
여기서 True가 0,2,3 번째에서 3명 False가 1,4 번째에서 2명이 반환된다.
비교연산자는 True값이 반환된 행만 추출해준다. 이것을 행 슬라이싱이라 한다.
df[ df['gender'] == 'M' ]
| name | gender | age | height | |
|---|---|---|---|---|
| 0 | 이철수 | M | 23 | 153.5 |
| 2 | 홍길동 | M | 21 | 163.4 |
| 3 | John Smith | M | 33 | 180.0 |
자료에서 선택해야할 경우의 수가 많은 경우 다음과 같은 .isin() 메소드를 사용할 수 있다. .isin 함수의 괄호 안에 선택할 문자 또는 숫자를 리스트 형태로 넣어준다.
예를 들어 나이가 25세와 33세인 사람만 슬라이싱 해보자.
우선 조건문을 보자
각 행마다 age가 25 또는 33 인지 확인하고 둘 중 하나가 맞디면 True, 그렇지 않으면 False를 반환한다.
df['age'].isin([25,33])
0 False
1 True
2 False
3 True
4 False
Name: age, dtype: bool
이렇게 반환된 True,False중 True의 행만 추출해주는 것을 볼 수 있다.
df[ df['age'].isin([25,33]) ]
| name | gender | age | height | |
|---|---|---|---|---|
| 1 | 김영희 | F | 25 | 175.3 |
| 3 | John Smith | M | 33 | 180.0 |
이번에는 조건문을 2개 썼을 경우이다.
만약 키가 160 이상인 남자 구성원만 슬라이싱 하려면 다음과 같은 명령어를 사용한다.
어떻게 이런 결과값이 나오는 지 확인해본다.
(df['gender'] == 'M') & (df['height'] >= 160.0)
0 False
1 False
2 True
3 True
4 False
dtype: bool
우선 성별이 남자인 조건문의 반환값이다.
df['gender'] == 'M'
0 True
1 False
2 True
3 True
4 False
Name: gender, dtype: bool
다음은 키가 160이상인 조건문의 반환값이다.
df['height'] >= 160.0
0 False
1 True
2 True
3 True
4 True
Name: height, dtype: bool
조건문이 2개 이고 여기선 &를 썼으므로 둘다 만족했을 때 True를 반환해준다.
True&True이면True를 반환Ture&False이면False를 반환False&False이면False를 반환
그러므로 둘 다 True를 만족하는 행은 2,3 번째 행뿐이므로 2개의 행만 반환한다.
df[ (df['gender'] == 'M') & (df['height'] >= 160.0) ]
| name | gender | age | height | |
|---|---|---|---|---|
| 2 | 홍길동 | M | 21 | 163.4 |
| 3 | John Smith | M | 33 | 180.0 |
이번에는 2개의 조건문 중에 하나 이상이 맞으면 슬라이싱하는 방법을 본다.
만약 나이가 30세 이하 또는 키가 160 미만인 행만 슬라이싱 하려면 다음과 같은 명령어를 사용한다.
이런 경우 | 즉 or 를 써서 둘 중 하나이상 맞으면 True를 반환하게 끔 해준다.
True|True이면True를 반환Ture|False이면True를 반환False|False이면False를 반환
첫번 째 조건문에서 만족하는 행은 0,1,2
df['age'] <= 30
0 True
1 True
2 True
3 False
4 False
Name: age, dtype: bool
두번 째 조건문에서 만족하는 행은 0
df['height'] < 160.0
0 True
1 False
2 False
3 False
4 False
Name: height, dtype: bool
두 조건문 중 한개라도 맞는 행은 0,1,2
(df['age'] <= 30) | (df['height'] < 160.0)
0 True
1 True
2 True
3 False
4 False
dtype: bool
최종 0,1,2 번째 행이 반환되는 걸 알 수 있다.
df[ (df['age'] <= 30) | (df['height'] < 160.0) ]
| name | gender | age | height | |
|---|---|---|---|---|
| 0 | 이철수 | M | 23 | 153.5 |
| 1 | 김영희 | F | 25 | 175.3 |
| 2 | 홍길동 | M | 21 | 163.4 |
데이터프레임에서 행을 조건에 따라서 슬라이싱 할 때 다음과 같은 규칙을 따른다.
비교연산자
<,<=,>,>=,!=,==을 사용한다.두 개 이상의 비교 표현식을 연결할 경우 또는(OR) 은
|을 사용하고 그리고(AND) 는&를 사용한다.비교 표현식을 연결할 경우 표현식은 언제나 괄호
()로 묶어준다.
참고로 두 개 이상의 비교 표현식을 연결할 경우 사용하는 연산자 | 와 & 는 비트단위연산자(bit-wise operator) 라고 부른다. 데이터프레임에 조건식을 사용하여 슬라이싱 할 경우 논리연산자 or 와 and 는 사용할 수 없다.
행과 열 선택#
이제 특정한 열과 행을 동시에 슬라이싱 해보자.
만약 키가 170 이상인 사람들의 이름이 필요하면 다음과 같이 슬라이싱할 수 있다. 괄호에서 첫 부분은 행에 대한 조건을 쓰고 컴마 , 로 분리한 후 열이름를 써준다.
여기서 유의해할 점은 행과 열을 동시에 슬라이싱할 경우 테이터프레임 이름 뒤에 .loc를 붙여주어야 한다. 만약 붙여주지 않으면 오류가 발생한다.
df_1 = df.loc[ (df['height'] >= 170.0) , 'name']
df_1
1 김영희
3 John Smith
Name: name, dtype: object
df.loc[ (df['gender'] == 'M') , ['name', 'height']]
| name | height | |
|---|---|---|
| 0 | 이철수 | 153.5 |
| 2 | 홍길동 | 163.4 |
| 3 | John Smith | 180.0 |
데이터프레임의 행과 열에 대한 인덱스를 숫자로 사용하여 슬라이싱하려면 데이터프레임 이름 뒤에 iloc 을 붙여주고 괄호 [] 안에 행과 열 순서의 위치를 써주면 된다. 이 경우 파이썬은 모든 위치는 0으로 시작하는데 유의하자.
하나의 위치가 아닌 여러개의 연속적인 위치는 x:y 형태이 범위 형식을 사용하여 지칭한다. 모든 열과 행을 지칭하는 경우 공란으로 넣거나 :을 사용한다.
df.iloc[0,0]
'이철수'
df.iloc[4,3]
165.7
df.iloc[3,1:3]
gender M
age 33
Name: 3, dtype: object
df.iloc[:,2]
0 23
1 25
2 21
3 33
4 45
Name: age, dtype: int64
df.iloc[0,:]
name 이철수
gender M
age 23
height 153.5
Name: 0, dtype: object
고용산재보험 가입 데이터#
실제 데이터로 실습해봅시다. 사용할 데이터는 근로복지공단에서 제공하는 2020년부터 2021년도까지 7개 광역시에 대한 고용보험과 산재보험에 가입한 음식점 수 현황입니다.
데이터 불러오기#
데이터를 불러오기 위해 pandas 패키기가 필요합니다.
그 안에 read_csv 라는 함수를 써서 csv 파일을 불러올 수 있습니다.
괄호 () 안에 파일경로를 붙여주면 해당경로의 csv파일을 가져옵니다.
df = pd.read_csv("https://uos-bigdata.github.io/lab_data/docs/assets/data_lab_bokji/data_food.csv")
df
| 시도 | 연도 | 산재_음식사업장수 | 고용_음식사업장수 | |
|---|---|---|---|---|
| 0 | 광주 | 2017.0 | 796 | 801 |
| 1 | 광주 | 2018.0 | 1121 | 1136 |
| 2 | 광주 | 2019.0 | 1674 | 1679 |
| 3 | 광주 | 2020.0 | 1757 | 1763 |
| 4 | 광주 | 2021.0 | 1727 | 1734 |
| 5 | 대구 | 2017.0 | 1367 | 1375 |
| 6 | 대구 | 2018.0 | 1739 | 1749 |
| 7 | 대구 | 2019.0 | 2523 | 2531 |
| 8 | 대구 | 2020.0 | 2428 | 2434 |
| 9 | 대구 | 2021.0 | 2619 | 2624 |
| 10 | 대전 | 2017.0 | 933 | 927 |
| 11 | 대전 | 2018.0 | 1093 | 1131 |
| 12 | 대전 | 2019.0 | 1588 | 1606 |
| 13 | 대전 | 2020.0 | 1767 | 1781 |
| 14 | 대전 | 2021.0 | 1634 | 1652 |
| 15 | 부산 | 2017.0 | 1713 | 1720 |
| 16 | 부산 | 2018.0 | 2159 | 2168 |
| 17 | 부산 | 2019.0 | 3205 | 3215 |
| 18 | 부산 | 2020.0 | 3508 | 3508 |
| 19 | 부산 | 2021.0 | 3829 | 3836 |
| 20 | 서울 | 2017.0 | 6069 | 6117 |
| 21 | 서울 | 2018.0 | 7967 | 8000 |
| 22 | 서울 | 2019.0 | 10576 | 10596 |
| 23 | 서울 | 2020.0 | 10612 | 10631 |
| 24 | 서울 | 2021.0 | 10752 | 10796 |
| 25 | 울산 | 2017.0 | 541 | 541 |
| 26 | 울산 | 2018.0 | 651 | 654 |
| 27 | 울산 | 2019.0 | 996 | 998 |
| 28 | 울산 | 2020.0 | 1137 | 1138 |
| 29 | 울산 | 2021.0 | 1046 | 1048 |
| 30 | 인천 | 2017.0 | 1319 | 1318 |
| 31 | 인천 | 2018.0 | 1817 | 1835 |
| 32 | 인천 | 2019.0 | 2718 | 2731 |
| 33 | 인천 | 2020.0 | 2886 | 2892 |
| 34 | 인천 | 2021.0 | 2891 | 2898 |
데이터 파악하기#
데이터를 파악하기 위해 info() 를 넣어주면 해당 데이터 행의 대략적인 정보를 확인 할 수 있습니다.
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 35 entries, 0 to 34
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 시도 35 non-null object
1 연도 35 non-null float64
2 산재_음식사업장수 35 non-null int64
3 고용_음식사업장수 35 non-null int64
dtypes: float64(1), int64(2), object(1)
memory usage: 1.2+ KB
앞에 배운 것을 이용해 봅니다.
열 선택을 해봅니다
2021년도 데이터만 불러봅니다.
행 선택이기 때문에 연도가 2021인 행만 True값을 반환합니다.
df['연도']==2021
0 False
1 False
2 False
3 False
4 True
5 False
6 False
7 False
8 False
9 True
10 False
11 False
12 False
13 False
14 True
15 False
16 False
17 False
18 False
19 True
20 False
21 False
22 False
23 False
24 True
25 False
26 False
27 False
28 False
29 True
30 False
31 False
32 False
33 False
34 True
Name: 연도, dtype: bool
True가 반환된 행만 슬라이싱 해줍니다.
df[df['연도']==2021]
| 시도 | 연도 | 산재_음식사업장수 | 고용_음식사업장수 | |
|---|---|---|---|---|
| 4 | 광주 | 2021.0 | 1727 | 1734 |
| 9 | 대구 | 2021.0 | 2619 | 2624 |
| 14 | 대전 | 2021.0 | 1634 | 1652 |
| 19 | 부산 | 2021.0 | 3829 | 3836 |
| 24 | 서울 | 2021.0 | 10752 | 10796 |
| 29 | 울산 | 2021.0 | 1046 | 1048 |
| 34 | 인천 | 2021.0 | 2891 | 2898 |
부산만 보고 싶다면 위에 경우와 같습니다.
df[df['시도']=='부산']
| 시도 | 연도 | 산재_음식사업장수 | 고용_음식사업장수 | |
|---|---|---|---|---|
| 15 | 부산 | 2017.0 | 1713 | 1720 |
| 16 | 부산 | 2018.0 | 2159 | 2168 |
| 17 | 부산 | 2019.0 | 3205 | 3215 |
| 18 | 부산 | 2020.0 | 3508 | 3508 |
| 19 | 부산 | 2021.0 | 3829 | 3836 |
이번에는 행까지 선택해봅니다.
고용 평균 근로자 수가 20이 넘는 지역을 파악해보려 합니다
df['고용_음식사업장수']>= 2000
0 False
1 False
2 False
3 False
4 False
5 False
6 False
7 True
8 True
9 True
10 False
11 False
12 False
13 False
14 False
15 False
16 True
17 True
18 True
19 True
20 True
21 True
22 True
23 True
24 True
25 False
26 False
27 False
28 False
29 False
30 False
31 False
32 True
33 True
34 True
Name: 고용_음식사업장수, dtype: bool
df[df['고용_음식사업장수']>= 2000]
| 시도 | 연도 | 산재_음식사업장수 | 고용_음식사업장수 | |
|---|---|---|---|---|
| 7 | 대구 | 2019.0 | 2523 | 2531 |
| 8 | 대구 | 2020.0 | 2428 | 2434 |
| 9 | 대구 | 2021.0 | 2619 | 2624 |
| 16 | 부산 | 2018.0 | 2159 | 2168 |
| 17 | 부산 | 2019.0 | 3205 | 3215 |
| 18 | 부산 | 2020.0 | 3508 | 3508 |
| 19 | 부산 | 2021.0 | 3829 | 3836 |
| 20 | 서울 | 2017.0 | 6069 | 6117 |
| 21 | 서울 | 2018.0 | 7967 | 8000 |
| 22 | 서울 | 2019.0 | 10576 | 10596 |
| 23 | 서울 | 2020.0 | 10612 | 10631 |
| 24 | 서울 | 2021.0 | 10752 | 10796 |
| 32 | 인천 | 2019.0 | 2718 | 2731 |
| 33 | 인천 | 2020.0 | 2886 | 2892 |
| 34 | 인천 | 2021.0 | 2891 | 2898 |
df['시도']
0 광주
1 광주
2 광주
3 광주
4 광주
5 대구
6 대구
7 대구
8 대구
9 대구
10 대전
11 대전
12 대전
13 대전
14 대전
15 부산
16 부산
17 부산
18 부산
19 부산
20 서울
21 서울
22 서울
23 서울
24 서울
25 울산
26 울산
27 울산
28 울산
29 울산
30 인천
31 인천
32 인천
33 인천
34 인천
Name: 시도, dtype: object
위에 실행했던 행과 열을 동시에 선택해 봅니다.
고용 평균근로자수가 20이 넘는 도시를 찾아보려 합니다
loc : location을 뜻합니다.
df['고용_음식사업장수']>= 2000 이 True인 행만 반환 해줄 것이고,
그 행들 중에서 시도인 열만 보고 싶으니 시도 만 반환해줍니다.
df.loc[(df['고용_음식사업장수']>= 2000), '시도']
7 대구
8 대구
9 대구
16 부산
17 부산
18 부산
19 부산
20 서울
21 서울
22 서울
23 서울
24 서울
32 인천
33 인천
34 인천
Name: 시도, dtype: object