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 이고 원소들은 문자열 MF 로 구성된 리스트이다.

'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,FalseTrue의 행만 추출해주는 것을 볼 수 있다.

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) 라고 부른다. 데이터프레임에 조건식을 사용하여 슬라이싱 할 경우 논리연산자 orand 는 사용할 수 없다.

행과 열 선택#

이제 특정한 열과 행을 동시에 슬라이싱 해보자.

만약 키가 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['고용_음식사업장수']>= 2000True인 행만 반환 해줄 것이고,

그 행들 중에서 시도인 열만 보고 싶으니 시도 만 반환해줍니다.

df.loc[(df['고용_음식사업장수']>= 2000), '시도']
7     대구
8     대구
9     대구
16    부산
17    부산
18    부산
19    부산
20    서울
21    서울
22    서울
23    서울
24    서울
32    인천
33    인천
34    인천
Name: 시도, dtype: object