jjinyeok 성장일지

Python 라이브러리 # 2 pandas - 2022/08/01~2022/08/02 본문

[KT AIVLE School]

Python 라이브러리 # 2 pandas - 2022/08/01~2022/08/02

jjinyeok 2022. 8. 5. 13:22

  지난 게시글에 이어 8월 1일부터 8월 2일까지 배운 데이터분석에서 중요한 라이브러리 중 하나인 pandas 라이브러리를 정리하고자 한다. 이전에 나는 pandas에 대해 드문드문 알고 있었지만 이번 강의를 통해 pandas에 대한 정리가 확실히 되었다.

pandas = data analysis and manipulation tool

1. 판다스의 구조

  판다스는 데이터프레임(Dataframe)과 시리즈(Series)로 구성할 수 있다. 데이터프레임에서 열(정보)를 띄어낸 것이 시리즈이고 반대로 시리즈의 집합체가 데이터프레임이다.

  먼저 데이터프레임을 살펴보도록 하자. 데이터프레임은 관계형 데이터베이스의 테이블 또는 엑셀 시트와 같은 2차원 구조 형태이다. 앞선 게시글의 분석할 수 있는 데이터의 모양과 같다. 먼저 행은 각각의 데이터 관측치를 의미한다. 각각의 행은 분석단위가 된다. 열은 요인(Feature)과 결과(Target)을 포함한 변수 속성을 의마한다. 각각의 열은 정보가 된다.

  다음으로 시리즈는 하나의 정보에 대한 데이터들의 집합을 의미한다. 즉 데이터프레임에서 하나의 열을 띄어낸 1차원 구조의 정보이다. 데이터를 분석할 때는 시리즈보다 데이터프레임이 더 중요하다.

 

2. 라이브러리 불러오기

  먼저 pandas 라이브러리를 불러와 사용해야한다.

import pandas as pd

 

3. 데이터프레임 만들기

  데이터프레임을 만드는 방법으로 pd.DataFrame() 함수를 사용하여 만드는 방법과 pd.read_csv() 함수를 통해 csv파일을 읽어와 만드는 방법 등이 있다.

  먼저 pd.DataFrame() 함수를 사용하여 딕셔너리 자료형이나 JSON 자료형 등을 데이터프레임으로 만드는 과정은 다음과 같다.

df = pd.DataFrame([{'name': 'jjinyeok', 'major': 'CE'}, {'name': 'gildong', 'major': 'BA'}])
print(df)
#        name major
# 0  jjinyeok    CE
# 1   gildong    BA

  다음으로 read_csv()함수를 사용하여 CSV 파일을 읽어와 데이터프레임으로 만드는 과정은 다음과 같다. 가장 일반적인 방법으로 잘 알아두자. URL을 통해서 CSV 파일을 읽어올 수도 있고 로컬에 있는 CSV 파일을 직접 읽어올 수도 있다.

titanic = pd.read_csv('titanic.csv')
print(titanic.head(3))
#    PassengerId  Survived
# 0          892         0
# 1          893         0
# 2          894         0

  read_csv 함수에는 CSV파일의 경로말고도 몇개의 option들을 추가로 입력할 수 있다.

  • sep: 구분자 지정 (default = ,(콤마))
  • header: 헤더가 될 행 번호 지정 (default = 0)
  • index_col: 인덱스 열 지정 (default = False)
  • names: 열 이름으로 사용할 문자열 리스트
  • skiprows: 처음 몇 줄을 무시할 것인지 지정

 

4. 데이터프레임 정보 확인하기

  데이터프레임 정보를 확인하기 위해 데이터 탐색이 필요하다.

  • head 메서드: 앞쪽 데이터 확인 (default = 5)
print(titanic.head())
#    PassengerId  Survived
# 0          892         0
# 1          893         0
# 2          894         0
# 3          895         1
# 4          896         0
print(titanic.head(3))
#    PassengerId  Survived
# 0          892         0
# 1          893         0
# 2          894         0
  • tail 메서드: 뒤쪽 데이터 확인 (default = 5)
print(titanic.tail())
#      PassengerId  Survived
# 413         1305         0
# 414         1306         1
# 415         1307         0
# 416         1308         0
# 417         1309         1
  • shape 속성: 데이터프레임 모양 확인 -> (행수, 열수) 형태
print(titanic.shape)
# (418, 2)
  • columns 속성: 열 이름 확인
print(titanic.columns)
# Index(['PassengerId', 'Survived'], dtype='object')
  • index 속성: 인덱스 정보 확인
print(titanic.index)
# RangeIndex(start=0, stop=418, step=1)
  • values 속성: 값 확인 -> 값만 떼어내서 NumPy 배열 형식으로 반환
print(titanic[:5].values) 
# [[892   0]
#  [893   0]
#  [894   0]
#  [895   1]
#  [896   0]]
  • dtypes 속성: 열 확인
print(titanic.dtypes)
# PassengerId    int64
# Survived       int64
# dtype: object
  • info 메서드: 인덱스, 열, 값 개수 데이터 형식 정보 등 확인
print(titanic.info())
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 418 entries, 0 to 417
# Data columns (total 2 columns):
#  #   Column       Non-Null Count  Dtype
# ---  ------       --------------  -----
#  0   PassengerId  418 non-null    int64
#  1   Survived     418 non-null    int64
# dtypes: int64(2)
# memory usage: 6.7 KB
  • describe 메서드: 기초 통계 정보 확인
print(titanic.describe())
#        PassengerId    Survived
# count   418.000000  418.000000
# mean   1100.500000    0.366029
# std     120.810458    0.482295
# min     892.000000    0.000000
# 25%     996.250000    0.000000
# 50%    1100.500000    0.000000
# 75%    1204.750000    1.000000
# max    1309.000000    1.000000

  또한 데이터를 정렬하여 데이터 정보를 확인할 수 있다. 정렬은 sort_index 메서드를 통해 인덱스를 기준으로 정렬하는 방식과 sort_values 메서드를 사용해 특정 열을 기준으로 정렬하는 것이 가능하다. 두 메서드 정렬 방법에 대해 사용하는 옵션이 동일한데 ascending=True (default) 옵션을 사용해 오름차순 정렬이 가능하고 ascending=False 옵션을 사용해 내림차순 정렬이 가능하다. 과정은 다음과 같다. 추가적으로 sort_values 메서드는 단일 열 정렬 뿐 아니라 복합 열 정렬도 지원함을 기억하도록 하자.

# sort_index를 통해 정렬하기
print(titanic.sort_index(ascending=False))
#      PassengerId  Survived
# 417         1309         1
# 416         1308         0
# 415         1307         0
# 414         1306         1
# 413         1305         0
# ..           ...       ...
# 4            896         0
# 3            895         1
# 2            894         0
# 1            893         0
# 0            892         0

# sort_values를 통해 정렬하기
print(titanic.sort_values(by=['Survived', 'PassengerId'], ascending=[False, True]))
#      PassengerId  Survived
# 3            895         1
# 8            900         1
# 12           904         1
# 14           906         1
# 15           907         1
# ..           ...       ...
# 407         1299         0
# 412         1304         0
# 413         1305         0
# 415         1307         0
# 416         1308         0

  고유값을 확인하는 것을 통해 데이터 정보를 확인할 수 있다. unique 메서드와 value_counts 메서드를 통해 고유값을 확인할 수 있다. 과정은 다음과 같다. 또한 dropna 옵션을 True로 지정하거나 생략하면 NaN값을 제외시킨다는 것을 기억하도록하자.

# unique 메서드를 사용해 고유값 확인하기
print(titanic['Survived'].unique())
# [0 1]

# sort_values 메서드를 사용해 고유값과 그 개수 확인하기
print(titanic['Survived'].value_counts()) 
# 0    265
# 1    153
# Name: Survived, dtype: int64

  데이터를 집계하여 데이터 정보를 간략하게 볼 수 있다. 기본 집계 메서드를 활용하여 볼 수 있는데 종류로는 sum - 합계, mean - 평균, max - 최댓값, min - 최솟값 등의 메서드가 있다. 모든 열에 대해서, 특정 열에 대해서, 특정 열들에 대해서 모두 사용할 수 있다. (사실 특정 열에 대해 집계하는 과정은 기존 데이터프레임으로부터 특정 열 시리즈를 떼어내어 집계 메서드를 사용하는 과정이고 특정 열들에 대해 집계하는 과정도 기존 데이터프레임으로부터 부분 데이터프레임을 떼어내어 집계 메서드를 사용하는 과정이다.) 정보 중 문자열 데이터에 대해 집계함수를 사용하면 예상치 못한 결과가 나올 수 있음에 주의하자.

# 모든 열에 대해 데이터 집계
print(titanic.sum())
# PassengerId    460009
# Survived          153
# dtype: int64

# 특정 열에 대해 데이터 집계
print(titanic['Survived'].sum())           
# 153

# 문자열에 대해 데이터 집계
# addr = 'address1'열에 '서울시 구로구 신도림동'이라는 데이터가 7개 저장되어 있는 데이터프레임
addr['address1'].sum()
# 서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동서울시 구로구 신도림동

 

5. 데이터프레임 조회하기

  데이터프레임을 조회하는 방법으로는 크게 특정 열을 조회하는 방법과 조건을 통해 조회하는 방법 2가지가 존재한다.

  먼저 특정 열을 조회하는 방법은 또 2가지 방법으로 나눌 수 있는데 DataFrame.Column 혹은 DataFrame['Column']과 같은 명령어를 사용해 1차원 시리즈로 조회하는 방법과 DataFrame[['Column']]과 같은 명령어를 사용해 2차원 데이터프레임으로 조회하는 방법이 있는데 이 방법은 칼럼 대신 칼럼 리스트를 입력하며 데이터를 데이터프레임형식으로 조회했다고 할 수 있다. 과정은 다음과 같다.

# 1차원 시리즈로 조회하기
print(titanic['Survived'])  
# 0      0
# 1      0
# 2      0
# 3      1
# 4      0
#       ..
# 413    0
# 414    1
# 415    0
# 416    0
# 417    1
# Name: Survived, Length: 418, dtype: int64

# 2차원 데이터프레임으로 조회하기
print(titanic[['PassengerId', 'Survived']]) 
#      PassengerId  Survived
# 0            892         0
# 1            893         0
# 2            894         0
# 3            895         1
# 4            896         0
# ..           ...       ...
# 413         1305         0
# 414         1306         1
# 415         1307         0
# 416         1308         0
# 417         1309         1
# 
# [418 rows x 2 columns]

  두번째로 조건으로 조회하는 방법이 있다 .loc[]이라는 속성을 사용하여 조회하는 방법인데 loc 내부에는 행 조건 (혹은 행인덱스 = 행 이름)과 열이름(생략 가능)이 들어온다. 이때도 위와 같이 열 이름이 1개라면 시리즈 형태로 리스트형식이라면 데이터프레임 형태로 결과가 나타난다. 과정은 다음과 같다.

print(titanic.loc[titanic['Survived'] == 1, ['PassengerId']])
#      PassengerId
# 3            895
# 8            900
# 12           904
# 14           906
# 15           907
# ..           ...
# 409         1301
# 410         1302
# 411         1303
# 414         1306
# 417         1309
# 
# [153 rows x 1 columns]

  and나 or 대신 &와 | 기호를 사용하여 여러 조건을 만족하는 행을 조회할 수 있다. 또한 isin과 between 메서드를 사용해서 조건을 만들 수 있는데 과정은 다음과 같다. 이때 between 메서드는 이상, 이하를 default로 사용함에 주의하자. 즉 between(0, 10)라면 0과 10을 모두 포함하는 사이값을 의미한다.

# 여러 조건을 만족하는 데이터 조회
print(titanic.loc[(titanic['Survived'] == 1) & (titanic['PassengerId'] <= 900), ['Survived', 'PassengerId']]) 
#    Survived  PassengerId
# 3         1          895
# 8         1          900

# isin 메서드를 사용하여 조건을 만족하는 데이터 조회
print(titanic.loc[titanic['PassengerId'].isin([800, 900, 1000, 1100, 1200]), ['PassengerId']]) 
#      PassengerId
# 8            900
# 108         1000
# 208         1100
# 308         1200

# between 메서드를 사용하여 조건을 만족하는 데이터 조회
print(titanic.loc[titanic['PassengerId'].between(990, 1000), ['PassengerId']])                 
#      PassengerId
# 98           990
# 99           991
# 100          992
# 101          993
# 102          994
# 103          995
# 104          996
# 105          997
# 106          998
# 107          999
# 108         1000

 

6. 데이터프레임 집계하기

  데이터들의 합(sum), 평균(mean), 최댓값(max), 최소값(min), 개수(count) 등을 기준으로 집계하는 것이 가능하다. 기본적인 문법은 DataFrame.groupby('Column1', as_index=False)['Column2'].집계메서드()이다. 이것은 Column1 별 Column2의 집계를 의미한다. 먼저 하나의 열에 대해 집계하는 과정은 다음과 같다. 아래의 과정은 생존(Survived) 별 승객번호(PassengerId)의 합(sum)을 의미한다.

# 열 하나 집계
print(titanic.groupby('Survived', as_index=False)['PassengerId'].sum()) 
#    Survived  PassengerId
# 0         0       292847
# 1         1       167162

  또한 여러 열을 집계하는 방법은 다음과 같다. DataFrame.groupby('Column1', as_index=False)['Column List'].집계메서드() 문법은  Column1 별 Column 리스트들의 집계를 의미한다. 과정은 다음과 같다. 즉 아래의 과정은 생존(Survived) 별 승객번호(PassengerId)와 생존여부(Survived)의 합(sum)을 보여준다.

print(titanic.groupby('Survived', as_index=False)[['PassengerId', 'Survived']].sum()) 
#    PassengerId  Survived
# 0       292847         0
# 1       167162       153

  마지막으로 agg 메서드를 통해 여러 열에 대해 여러 집계를 한번에 수행하는 것이 가능하다. DataFrame.groupby('Column1', as_index=False)['Column List'].agg([집계 메서드 명 List]) 문법은 Column1 별 Column 리스트들의 집계들을 의미한다. 과정은 다음과 같다. 아래의 과정을 통해 생존(Survived) 별 승객번호(PassengerId)와 생존여부(Survived)의 합(sum)과 최댓값(max), 개수(count)를 보여준다.

print(titanic.groupby('Survived', as_index=False)[['PassengerId', 'Survived']].agg(['sum', 'max', 'count']))
#          PassengerId             Survived
#                  sum   max count      sum max count
# Survived
# 0             292847  1308   265        0   0   265
# 1             167162  1309   153      153   1   153

 

7. 데이터프레임 변경하기

  먼저 열 이름을 변경하고 열을 추가하고 삭제하는 방법을 보자. 열 이름을 변경하는 방법은 모든 열 이름을 입력하여 변경하는 방법과 rename 메서드를 이용하여 지정한 열 이름을 변경하는 방법이 있다. HTTP 메서드 중 PUT과 PATCH의 차이같은 느낌이랄까. rename 메서드를 사용할 때 inplace=True 옵션을 주어야 데이터프레임의 열 이름이 실제로 변경된다. 혹은 DataFrame = DataFrame.rename(...)과 같은 방법으로도 실제로 변경시킬 수 있다.

# 모든 열 이름 변경
titanic.columns = ['Pid', 'Surv']
print(titanic)
#       Pid  Surv
# 0     892     0
# 1     893     0
# 2     894     0
# 3     895     1
# 4     896     0
# ..    ...   ...
# 413  1305     0
# 414  1306     1
# 415  1307     0
# 416  1308     0
# 417  1309     1
# 
# [418 rows x 2 columns]

# 지정한 열 이름 변경
titanic.rename(columns={'Pid': 'PassengerId', 'Surv': 'Survived'}, inplace=True) 
print(titanic)
#      PassengerId  Survived
# 0            892         0
# 1            893         0
# 2            894         0
# 3            895         1
# 4            896         0
# ..           ...       ...
# 413         1305         0
# 414         1306         1
# 415         1307         0
# 416         1308         0
# 417         1309         1
# 
# [418 rows x 2 columns]

  열 추가하기는 딕셔너리에 Key-Value 쌍을 저장하듯 추가하면 데이터프레임에 새로운 열이 만들어진다. insert라는 메서드를 이용해 지정한 위치에 열을 추가하는 방법도 다루었지만 실무에서는 열의 물리적인 위치는 신경쓰지 않는다. 열 추가하기는 기본적으로 맨 뒤에 열을 추가하는 방법을 사용한다.

# 맨 뒤에 열 추가하기
titanic['Pid + Surv'] = titanic['PassengerId'] - titanic['Survived']
print(titanic)
#      PassengerId  Survived  Pid + Surv
# 0            892         0         892
# 1            893         0         893
# 2            894         0         894
# 3            895         1         894
# 4            896         0         896
# ..           ...       ...         ...
# 413         1305         0        1305
# 414         1306         1        1305
# 415         1307         0        1307
# 416         1308         0        1308
# 417         1309         1        1308
#
# [418 rows x 3 columns]

# 지정한 위치에 열 추가하기
titanic.insert(1, 'Pid * Surv', titanic['PassengerId'] * titanic['Survived']) 
print(titanic)
#      PassengerId  Pid * Surv  Survived  Pid + Surv
# 0            892           0         0         892
# 1            893           0         0         893
# 2            894           0         0         894
# 3            895         895         1         894
# 4            896           0         0         896
# ..           ...         ...       ...         ...
# 413         1305           0         0        1305
# 414         1306        1306         1        1305
# 415         1307           0         0        1307
# 416         1308           0         0        1308
# 417         1309        1309         1        1308
# 
# [418 rows x 4 columns]

  열을 삭제하는 방법이다. 데이터프레임에서 열을 삭제하면 되돌리기가 불가능하기 때문에 조심하여 사용해야 한다. drop 메서드를 사용해 열을 삭제한다. axis 옵션의 default 값이 0이기 때문에 drop 메서드는 기본적으로 행을 삭제한다. 따라서 열을 삭제하기 위해서 axis=1로 설정한다. rename 메서드와 같이 drop 메서드를 사용할 때 inplace=True 옵션을 주어야 데이터프레임의 열이 실제로 삭제된다. 과정은 다음과 같다.

titanic.drop(['Pid + Surv', 'Pid * Surv'], axis=1, inplace=True)
print(titanic)
#      PassengerId  Survived
# 0            892         0
# 1            893         0
# 2            894         0
# 3            895         1
# 4            896         0
# ..           ...       ...
# 413         1305         0
# 414         1306         1
# 415         1307         0
# 416         1308         0
# 417         1309         1
# 
# [418 rows x 2 columns]

  다음은 map() 메서드를 살펴보도록 하겠다. 실무에서는 범주형 값을 수치형 값으로 변경할때 사용된다고 한다. 하나의 시리즈에 대해 바뀔 값과 바꿀 값을 지정해두는 방법으로 사용이 가능하다. 과정은 다음과 같다.

# 0 -> False, 1 -> True
titanic['Survived'] = titanic['Survived'].map({0: False, 1: True}) 
print(titanic)
#      PassengerId  Survived
# 0            892     False
# 1            893     False
# 2            894     False
# 3            895      True
# 4            896     False
# ..           ...       ...
# 413         1305     False
# 414         1306      True
# 415         1307     False
# 416         1308     False
# 417         1309      True
# 
# [418 rows x 2 columns]

  마지막으로 값 크기를 기준으로 지정한 개수의 범위로 나누어 범주 값을 지정하는 cut() 메서드를 살펴보겠다. map() 메서드와 마찬가지로 하나의 시리즈에 대해 적용이 가능하다. 사용 과정은 다음과 같다. 문법은 pd.cut(Series, 범주 개수 or 구간 지정, labels=변경될 이름(범주))이다. 과정은 다음과 같다. 아래 과정에서 구간을 지정하면 (800, 900], (900, 1000], (1000, 1100], ... (1300, 1400] 과 같은 방법으로 구간이 나뉘게 된다. 즉 범위는 리스트의 개수보다 1이 적다. 유의하자.

# 조건에 따라 범위로 나누어 범주 값 지정하기
titanic['PassengerId'] = pd.cut(titanic['PassengerId'], [800, 900, 1000, 1100, 1200, 1300, 1400], labels=[800, 900, 1000, 1100, 1200, 1300])
print(titanic)
#     PassengerId  Survived
# 0           800     False
# 1           800     False
# 2           800     False
# 3           800      True
# 4           800     False
# ..          ...       ...
# 413        1300     False
# 414        1300      True
# 415        1300     False
# 416        1300     False
# 417        1300      True

 

    판다스라는 정말 중요한 라이브러리를 배우고 정리해보았다. 인공지능 수업을 들었을 때 데이터를 간략히 요약해서 보여주는 용도 정도로 알고 있었지만 데이터 분석과 요약 전처리 모든 부분에서 사용할 수 있을 것 같다. 강사님께서도 어쩌면 모델링보다 더 중요한 부분이 판다스라고 하셨고 그 부분은 아직 내공이 부족한 나도 어느정도 공감이 되었다. 미니 프로젝트 전까지 판다스를 더 공부해봐야겠다.

 

  크롤링 수업을 진행해주시는 강사님께서는 이 자료를 통해 더 판다스를 공부하길 권하셨다. 꼭 미니 프로젝트 전까지 공부하고 판다스에 내공을 쌓아야겠다.

https://pandas.pydata.org/docs/user_guide/10min.html

 

10 minutes to pandas — pandas 1.4.3 documentation

Note While standard Python / NumPy expressions for selecting and setting are intuitive and come in handy for interactive work, for production code, we recommend the optimized pandas data access methods, .at, .iat, .loc and .iloc.

pandas.pydata.org

 

Comments