Pandas 라이브러리 사용법

BoostCamp AI Tech

Python

Pandas

01/27/2021


본 정리 내용은 Naver BoostCamp AI Tech의 edwith에서 수강한 내용을 정리한 것입니다.
사실과 다른 부분이 있거나, 수정이 필요한 사항은 댓글로 남겨주세요.


Pandas

panel datas에서 나온 이름으로, 구조화된 데이터의 처리를 지원하는 Python의 라이브러리이다. Python의 엑셀이라고 할 수 있다.

  • 고성능 array 계산용 라이브러리인 numpy와 통합하여 강력한 스프레드시트 처리 기능을 제공한다.
  • 인덱싱, 연산용 함수, 전처리 함수 등을 제공한다.
  • 데이터 처리 및 통계 분석을 위해 사용된다.
  • Tabular 데이터(테이블형 데이터)를 다루는 데에 최적화되어있다.

pandas_data_type

이 중, Data Table 전체를 포함하는 객체를 DataFrame, Column 하나에 해당하는 데이터셋 객체를 Series라고 한다.

Series

PYTHON
list_data = [1,2,3,4,5]
example_obj = Series(data = list_data)
example_obj
'''
0 1
1 2
2 3
3 4
4 5
dtype: int64
'''

data 파라미터를 받아 객체를 생성하며, Numpyndarray 를 기반으로 만들어진, Pandas 에서 사용하기 위한 wrapper 객체라고 볼수도 있다.(Subclass of numpy.ndarray)

특이한 점은, 위와 같이 [1,2,3,4,5] 라는 데이터만 들어가는것이 아니라, 이 데이터의 인덱스 값 [0,1,2,3,4] 도 같이 저장된다. 이 인덱스값은 문자열로도 지정 가능하다.

Series 객체를 생성할 때, Index를 기준으로 생성하므로 만약 data가 없는 index가 있다면 NaN값이 채워진다.

  • data와 index를 따로 명시하는 대신 dict 타입을 넣어 한번에 지정할 수도 있다.
  • name으로 Series 객체 자체의 이름을 정해줄 수 있다.
  • index.name 으로 인덱스의 이름을 지정해줄 수 있다.
  • as_type 으로 데이터 타입을 변경할 수 있다.

PYTHON
# 인덱스 문자열로 바꾸기
list_data = [1,2,3,4,5]
list_name = ["a","b","c","d","e"]
example_obj = Series(data = list_data, index=list_name)
example_obj
'''
a 1
b 2
c 3
d 4
e 5
dtype: int64
'''
# dict 타입으로 생성하기
dict_data = {"a":1, "b":2, "c":3, "d":4, "e":5}
example_obj = Series(dict_data, dtype=np.float32, name="example_data")
# series 객체 이름 지정
example_obj.name = "number"
# index 이름 지정
example_obj.index.name = "alphabet"
# 데이터 타입(dtype) 변경하기
example_obj = example_obj.astype(int)

Dataframe

Numpy 의 2차원 ndarray 와 비슷한 객체이며, Series 와 달리 (row) index 뿐만 아니라 column index도 있다. 각 컬럼은 다른 데이터 타입을 가질 수 있으며, 컬럼을 떼고 붙일 수 있으므로 데이터프레임의 전체 사이즈는 mutable하다.

Series 객체를 생성할 때처럼, Index를 기준으로 생성하므로 만약 data가 없는 row 또는 column index가 있다면 NaN값이 채워진다.

  • 인덱싱으로 lociloc 을 사용할 수 있다. (Series 객체도 통용)
    • loc 은 실제 index name과 일치하게 사용해야한다. (숫자, 문자열)
    • iloc 은 index의 position 값을 사용한다.(0부터 n까지의 숫자)
    • 두 인덱싱 모두 row와 column을 모두 지정해줄 수 있다.
  • column에 새로운 데이터를 할당할 수 있다.
    • comparison 등으로 boolean 값을 넣을 수도 있다. (Numpyfancy index )
  • df.T 로 row와 column 인덱스를 바꿀 수 있다.
  • values 를 사용하여 데이터 ndarray를 뽑아낼 수 있다.
  • 컬럼을 삭제할 때, 두가지 방법을 이용할 수있다.
    • 컬럼 삭제 시, del df['컬럼명'] - 메모리 주소까지 삭제
    • df.drop('컬럼명', axis=n) 원본 데이터 프레임은 변경하지 않고, 해당 컬럼을 삭제한 데이터프레임을 반환한다.

PYTHON
raw_data = {'first_name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'],
'last_name': ['Miller', 'Jacobson', 'Ali', 'Milner', 'Cooze'],
'age': [42, 52, 36, 24, 73],
'city': ['San Francisco', 'Baltimore', 'Miami', 'Douglas', 'Boston']}
df = pd.DataFrame(raw_data, columns = ['first_name', 'last_name', 'age', 'city'])
df.first_name # == df["first_name"], series 데이터형
# 인덱싱
s = pd.Series(np.nan, index=[49,48, 1, 2])
s.loc[:1] # 인덱스 이름이 1인 row 까지만
'''
49 NaN
48 NaN
1 NaN
'''
s.iloc(:1] # 인덱스 위치가 1인 row까지만
'''
49 NaN
'''
# column에 새로운 데이터 할당
df.debt = df.age > 40 # column 'debt'에 comparison의 T/F 값 입력하여 붙임

Selection & Drop

Selection 방식

  • 데이터의 타입을 체킹할 때 head().T 를 사용하여 컬럼에 올바른 값이 들어갔는지 확인하기도 한다.
  • n개의 컬럼명을 리스트로 지정하여 해당 컬럼 데이터들을 뽑아올 수 있다.
  • 컬럼명을 지정하지 않았을 시, index number로 해당 row를 뽑아올 수 있다.
  • Numpyfancy index처럼, 조건식을 넣어 사용할 수도 있다.
  • Index name 변경도 가능하다.

PYTHON
# 컬럼 데이터 타입 확인
df.head(3).T
# 컬럼명 지정
df["a"].head(2)
df[["a", "b", "c"]].head(3)
# 컬럼명 없이 사용하는 인덱스 지정은 row를 표시한다.
df[:3] # == df[[0,1,2]], 0,1,2 row 표시
# 조건식 넣어 selection
df[20 < "age" < 40]

loc, iloc 을 활용한 selection

loc, iloc을 활용한 selection도 확인해보자.

  • 기본 방식
    • 컬럼명을 명시하고, index number를 넣어 row의 개수를 지정한다.
  • loc
    • index name을 넣어 row를 지정한 뒤, 컬럼명을 명시한다.
  • iloc
    • 컬럼 number를 지정한 뒤, index number를 지정해 row도 명시한다.

PYTHON
# basic
# 컬럼명과 row index 숫자
df[["name","street"]][:2]
# loc
# row index 명과 컬럼명
df.loc[['c','e'],["name","street"]]
# iloc
# 컬럼 숫자와 row index 숫자
df.iloc[:2,:2]

Index 재구성

두 가지 방식이 있다.

  1. 직접 지정
  2. reset_index 함수 사용

PYTHON
# 직접 지정해주기
df.index = list(range(0,10))
# 디폴트 인덱스를 추가한 데이터 프레임을 반환
# 기존 인덱스를 대체하고싶다면 drop=True 옵션
df.reset_index(drop=True)
# 단, inplace=True 옵션을 사용하면 원본 데이터 프레임 변환을 '적용'시킨다.

일반적으로 데이터프레임은 원본을 유지하는것이 컨벤션이지만, 부득이하게 변경해야할 경우 inplace=True 옵션을 사용하여 변환상태를 '적용'시킨다.

Drop

  • df.drop(n) 은 인덱스를 지정하여 해당 row를 삭제한 데이터프레임을 반환한다.
  • axis=1 옵션을 지정하여 column을 삭제할 수 있다.
  • 마찬가지로, inplace=True 옵션을 사용하여 원본 데이터프레임을 수정할 수 있다.

PYTHON
# 1번 row 삭제
df.drop(1)
# 'city' column 삭제
df.drop("city",axis=1)

매트릭스 변환

이외에도, as_matrix() 함수로 Numpy ndarray 형태로 변환할 수 있다.

PYTHON
matrix = df.as_matrix()

Operations

Series Operation

모든 연산은 (row) index를 기준으로 연산을 수행한다.

따라서 겹치는 index가 없을 경우 NaN값을 반환한다.

PYTHON
s1 = Series(range(1,6), index=list("abcde"))
s2 = Series(range(5,11), index=list("bcdefg"))
# 겹치는 index는 b,c,d,e
s1 + s2 # == s1.add(s2)
'''
a NaN
b 7.0
c 9.0
d 11.0
e 13.0
f NaN
g NaN
dtype: float64
'''

Dataframe Operation

Series 는 index만 체크했지만, Dataframe은 column값과 index를 같이 본다.

겹치는 셀이 없을 경우 NaN 을 반환하지만, fill_value= 옵션을 사용해 다른 값을 디폴트로 지정할 수 있다.

PYTHON
df1 = DataFrame(
np.arange(9).reshape(3,3),
columns=list("abc"))
df2 = DataFrame(
np.arange(16).reshape(4,4),
columns=list("abcd"))
# df2.loc[3]과 df2["d"]가 겹치지 않음
# df1 + df2
df1.add(df2,fill_value=0) # 겹치지 않아 NaN 값이 들어갈 위치를 0으로 채움

Series + Dataframe

SeriesDataframe 은 다른 타입이므로 같은 colum을 가진 것이 아니라면 모든 데이터가 NaN으로 채워져 제대로 연산이 되지 않는다.

axis= 옵션을 명시해주어야 해당 축을 기준으로 broadcasting을 수행한다.

PYTHON
df = DataFrame(
np.arange(16).reshape(4,4),
columns=list("abcd"))
s = Series(
np.arange(10,14),
index=list("abcd"))
s2 = Series(np.arange(10,14))
# Series가 Dataframe의 column과 같은 index을 가져 바로 row로 변환되는 경우
df + s
# Series가 Dataframe의 column과 다른 index을 가져 row로 변환되지 않는 경우
df + s2 # 모든 값이 NaN으로 채워짐
# axis를 기준으로 row broadcasting 수행
df.add(s2, axis=0)

row_broadcasting

lambda, map, apply

map

pandasSeries type 데이터에는 map 함수를 사용할 수 있다.

이 때, lambda와 조합할 수 있고, function 대신 dict, sequence 형 자료 등으로 대체도 가능하다.

비슷한 기능으로 replace 가 있다.
map 함수의 기능 중 데이터 변환기능만 담당한다. 즉, map 처럼 데이터에 함수를 적용할 수 없고, dict에서 정해진 value값으로 바꿔주기만 한다.

PYTHON
# number_df의 값들을 제곱하는 mapping
number_df.map(lambda x: x**2).head(5)
# str 성별값을 0,1 코드값으로 바꾸어 sex_code 컬럼에 추가하는 mapping
df["sex_code"] = df.sex.map({"male":0, "female":1})
# str 성별값을 0,1 코드값으로 변환하여 출력 - replace
df.sex.replace({"male":0, "female":1}).head()
# to_replace=변환할 키값(from), value=변환하여 저장할 값(to)
# to_replace에 해당하는 값을 value에 있는 값으로 변환시키겠다
df["race"].replace(to_replace=key, value=value, inplace=True)

apply

map 함수와 달리, Series 전체 단위에 해당 함수를 적용한다.

  • 입력값을 Dataframe, Series 모두 받을 수 있다.
  • 스칼라 값 이외에 Series 값의 반환도 가능하다.

PYTHON
df_info = df[["earn", "height","age"]]
f = lambda x : x.max() - x.min()
df_info.apply(f)
'''
earn 318047.708444
height 19.870000
age 73.000000
dtype: float64
'''
# Series 값 반환
def f(x):
return Series([x.min(), x.max(), x.mean()],
index=["min", "max", "mean"])
df_info.apply(f)
'''
earn height age
min -98.580489 57.34000 22.000000
max 317949.127955 77.21000 95.000000
mean 32446.292622 66.59264 45.32849
'''

applymap

apply와는 다르게, Series 단위가 아닌 element 단위로 함수를 적용한다.

  • applydataframe 이 아닌 Series 에 적용시키면, applymap과 동일한 기능을 수행한다.
PYTHON
f = lambda x : -x
df_info.applymap(f).head(5)
# 위의 코드는 아래 코드와 동일한 기능을 수행한다.
# f = lambda x : -x
# df_info["earn"].apply(f).head(5)

Pandas Built-in Function

describe

Numeric Type 데이터들의 요약정보를 보여준다.

PYTHON
df.describe()

describe

unique

Series 데이터에 있는 유일한 값(중복을 제외한 값)들을 list로 반환한다.

PYTHON
df.race.unique()
'''
array(['white', 'asian', 'hispanic', 'black', 'other'], dtype=object)
'''

sum

기본적인 column 또는 row 값의 합연산을 지원한다.

이외에도 비슷한 기능의 함수들이 많다.

  • sub , mean, min, max , count, median , mad, var

PYTHON
# 컬럼별 합
df.sum(axis=0)
# row별 합
df.sum(axis=1)

isnull

column 또는 row 값 중 NaN (null) 값의 index를 반환한다.

  • sum 함수를 체이닝하여 Null인 셀이 몇개 있는지 확인할 수도 있다.

PYTHON
# null인 data의 index를 반환
df.isnull()
# Null인 셀 개수 확인
df.isnull().sum()

sort_values

column 값을 기준으로 데이터를 정렬한다.

  • 옵션을 명시해 오름차순, 내림차순등을 지정할 수 있다.

PYTHON
# ascending=False 시 내림차순
df.sort_values(["age","earn"], ascending=True).head()

Correlation & Covariance

상관계수와 공분산을 구해준다.

  • corr , cov , corrwith

PYTHON
# df.[컬럼1].함수(df.[컬럼2])
df.age.corr(df.earn)
df.age.cov(df.earn)
df.corrwith(df.earn)
# 모든 컬럼들간의 상관관계를 다 보여준다
df.corr()

통계함수

Groupby

통계 데이터를 내기 위한 함수로, 특정 컬럼의 값을 지정해당 값을 가진 row들을 SeriesGroupBy 객체로 묶고, 체이닝 통계 연산으로 통계화하여 보여준다.

BASH
# phone_data.csv 파일 다운로드
!wget https://www.shanelynn.ie/wp-content/uploads/2015/06/phone_data.csv
PYTHON
df_phone = pd.read_csv('./data/phone_data.csv')
df_phone.dtypes
'''
...
date object
...
'''
# 문자열 타입의 date 컬럼 값을 각각(apply) 파싱하여 datetime 타입으로 변환
# parse 함수의 argument에서 '일(day)'가 '월(month)'보다 먼저나온다면 dayfirst=True
df_phone['date'] = df_phone['date'].apply(dateutil.parser.parse, dayfirst=True)
df_phone.dtypes
'''
date datetime64[ns]
'''
# datetime 타입의 월별로 묶어, duration(통화시간)의 합계를 matplotlib로 그래프 표시
df_phone.groupby("month")["duration"].sum().plot()
# month와 item별로 묶어 duration count
# unstack으로 row 인덱스 값들을 column 인덱스로 재구성해 볼 수 있다.
df_phone.groupby(['month','item'])['duration'].count().unstack().plot()
# month로 묶되, 인덱스로 삼지는 말것(as_index=False)
# duration에는 sum을 적용시킬것(agg({"duration":"sum"}))
# agg함수는 그룹에 대하여 사용자가 정의한 집계함수를 적용할 수 있다.
df_phone.groupby("month", as_index=False).agg({"duration":"sum"})
# df_phone.groupby("month").agg({"duration":"sum"}).reset_index # 비슷한 결과
# group 타입 객체를 만들었다면
group.add_prefix('duration_') # 컬럼이름에 접두사 추가하기

자세한 설명은 다음 블로그를 참고한다.

[Python Data Analysis]24.데이터 그룹화 함수 이해하기

Pivot Table

컬럼에 labeling값을 추가하여 Value에 numeric type 값을 aggregation하는 형태

groupby + unstack의 조합으로도 수행할 수 있지만, 액셀을 사용하는것이 익숙하다면 pivot_table을 사용하는것이 좀 더 쉽다.

BASH
# 각 데이터의 value 위치에 들어갈 값은 ["rating"] 컬럼값들 중 하나로 정한다.
# critic의 값들을 row index로 하고, title의 값들을 columns로 구성한다.
# 각 value에 aggfunction "sum"을 적용하고, NaN값은 0으로 채운다.
df_movie.pivot_table(["rating"], index=df_movie.critic, columns=df_movie.title,
aggfunc="sum", fill_value=0)

Crosstab

두 컬럼의 교차 빈도, 비율, 덧셈 등을 구할 때 사용하는 함수로, pivot_table의 특수 형태이다.

  • User-Item Rating 행렬등을 만들 때 사용한다.
BASH
# 세 함수는 같은 역할을 한다.
df_movie.groupby(["critic","title"]).agg({"rating":"first"}).unstack().fillna(0)
df_movie.pivot_table(["rating"], index=df_movie.critic, columns=df_movie.title,
aggfunc="sum", fill_value=0)
pd.crosstab(index=df_movie.critic,columns=df_movie.title,values=df_movie.rating,
aggfunc="first").fillna(0)

Merge & Concat

Merge

SQL에서 많이 사용하는 Merge와 같은 기능으로, 겹치는 컬럼 데이터를 기준으로 두개의 데이터프레임을 하나로 합치는 기능이다.

  • 두 데이터프레임에 같은 이름의 컬럼이 있다면, on='column_name' 옵션으로 기준점을 만든다.
  • 두 컬럼이 데이터는 같지만 이름은 다르다면, left_on='left_column_name' ,right_on='right_column_name' 으로 기준점을 만든다.

JOIN의 종류

joins

  • how= 옵션을 이용해 join의 종류를 지정해줄 수 있다.

    • how=inner : 디폴트로, 두 컬럼에서 겹치는 값을 기준으로 인덱스를 구성한다.
    • how=left(right) : left(right) 컬럼의 값을 기준으로 인덱스를 구성
    • how=outer : 두 컬럼의 모든 값을 인덱스로 사용하며, 없는 값은 NaN을 넣는다.
  • index 컬럼을 기준으로 테이블을 그대로 붙일수도 있다.

    • right_index=True, left_index=True
BASH
# 같은 이름의 컬럼을 기준으로 join
pd.merge(df_a, df_b, on='subject_id')
# 다른 이름의 컬럼을 하나의 컬럼으로 보고, 이를 기준으로 join
pd.merge(df_a, df_b, left_on='subject_id_a', right_on='subject_id_b')
# left join
pd.merge(df_a, df_b, on='subject_id', how='left')
# outer join
pd.merge(df_a, df_b, on='subject_id', how='outer')
# 인덱스를 기준으로 join
pd.merge(df_a, df_b, right_index=True, left_index=True)

concat

같은 형태의 데이터를 붙이는 연산함수다.

  • append 를 사용해서 비슷한 결과를 낼 수 있다.
  • 디폴트는 세로로 붙이지만(행 추가), 가로로 붙일수도 있다(열 추가).
    • 물론, 세로로 붙일 경우 같은 컬럼을 가지고 있어야 붙일 수 있다.
    • axis=1 옵션으로 가로로 붙일 수 있다.
BASH
# 세로로 붙이기
df_new = pd.concat([df_a, df_b])
df_new.reset_index() # 해주지 않으면, 인덱스가 그대로 붙어 0,1,2,3,0,1,2, ... 형태가 된다.
#df_a.append(df_b) # 거의 같은 기능을 가진다.
# 가로로 붙이기
df_new = pd.concat([df_a, df_b], axis=1)
df_new.reset_index()

Persistence

Pandas에서 I/O를 사용해 영속성 있는 데이터를 사용할 수 있다.

Database Connection

데이터 로딩시, db connection 기능을 제공한다.

BASH
import sqlite3 # pymysql을 미리 설치할 것!
conn = sqlite3.connect(".sqlite_example.db")
cur = conn.cursor()
cur.execute("select * from name limit 5;") # SQL문 직접 사용 가능
results = cur.fetchall()
results

XLS Persistence

데이터프레임 단위로 엑셀값을 추출하거나 쓸 수 있다.

openpyxl 또는 XlsxWriter 라이브러리를 설치해야한다.

BASH
writer = pd.ExcelWriter('./data/df_routes.xlsx', engine='xlsxwriter')
# 액셀 형태로 저장
df_routes.to_excel(writer, sheet_name='Sheet1')

Pickle Persistence

엑셀과 동일하게 피클형태로도 읽고 쓸 수 있다.

BASH
df_routes_pickle = pd.read_pickle("./data/df_routes.pickle")
df_routes_pickle.head()

WRITTEN BY

알파카의 Always Awake Devlog

Seoul