최근 ChatGPT로 인해 자연어처리에 대한 관심이 높아지고 있는데 이를 잘 하기 위해서는 지저분한 데이터들이 들어왔을때에 깨끗하게 정리하기 위한 Regular Expression이 중요하고, 다양한 형태로 가공하기 위해 Pandas가 매우 매우 중요하다. 오늘은 Pandas에 대해 핵심적인 내용들을 정리해보도록 하겠다.
1. 판다스 개념 잡기
판다스는 가로 행이 아닌, 세로 열을 기준으로 만든 데이터구조이다. 가로가 아닌 세로 열의 관점에서 모든 데이터를 바라보아야 한다.이 개념이 머리속에 확실하게 와닿지 않는다면 판다스를 쓸데마다 항상 헷갈리고 오히려 불편함을 느낄 것이다. 예를들면, 주로 우리는 일상 업무속에서 어제까지 데이터 모아서 보자 등의 Row, 가로 행 기준에서 데이터를 인식하는 경향이 있기 때문이다. Row는 어떤 데이터의 기준이 아니라 세로 열들을 담아야하는 처리 기준으로 바라보아야 한다. 판다스에서는 이것을 Bucket 개념으로 다룬다. 즉, 아래의 경우 날짜별 데이터를 모은 것이 아니라, 상품명/색상/가격별 데이터를 모은 것인데 2022~2023년 내용들만 담는것이다. 그말이 그말같지만 정말 미묘한 개념적 차이를 뼈속까지 확실히 느껴야 앞으로 다양한 데이터 사이언스 작업들을 할때에 혼선되지 않을 것이다. 부디 꼭 이 개념이 중요함을 인지하기 바란다.
- 시리즈 개념
우리는 무의식중에 가로행을 기준으로 생각할때가 많다. 1시에 한일들, 2시에 한일들... 하지만 판다스는 세로열이 중심이다. 판다스는 이러한 많은 열들을 모아서 다양한 처리를 도와주는 라이브러리라고 생각하면 된다. 여기서 말하는 세로열은 Series이고, Series를 모은 것이 DataFrame이다. 예를 들어, 아래의 화면은 순위 / 제목 / 스튜디오 / 매출 / 년도 총 5개의 시리즈가 모인 데이터프레임이다.
시리즈 개념이 명확하게 와닿지 않으면 판다스를 쓰면 안될정도로 반드시 몸으로 느껴야한다. 안그러면 데이터를 뽑고 추가하고 병합하고 나누고 등등... 할때마다 계~~~속 헷갈리고 자신을 괴롭히게 된다. 꼭! 꼭! 기억하기를 간절히 바란다. 이후에는 세로 열이나 컬럼이라고 하지 않고 시리즈(Series)라고 지칭하겠다.
- 인덱스
인덱스도 마찬가지로 또하나의 시리즈로 인식을 해야한다. 인덱싱을 위한 인덱스 시리즈를 추가할 수도 있고 기존 시리지를 인덱스로 사용할 수도 있다. 참고로, 인덱스는 별도 분리된 공간에 존재한다고 생각하여야 한다. 그래서 인덱스를 "Title"로 잡았다고 기존 "Title"과 중복되는 것이 아니다. 방법은 csv 불러올때 미리 지정이 가능하고 이후에 별도로 지정도 가능하다. 참고로, 인덱스로 사용하려면 가장 하위레벨 정보를 사용해야한다. 그룹화할 수 있는 시리즈로 인덱스를 잡으면 통계형태로 재정리되니 주의해야한다. No index 그림과 , Title Index, Studio Index 그림을 비교해보길 바란다.
pd.read_csv("movies.csv", index_col = "Title")
df = df.set_index('Studio')
- 기타: 여러가지 정보를 얻을 수 있는 함수들은 특별한 설명이 필요없어서 다음을 참조바란다
import pandas as pd
df = pd.read_csv('data/movies.csv')
print('head() ---------------------------')
print(df.head())
print('\n\ntail() ---------------------------')
print(df.tail())
print('\n\ninfo() ---------------------------')
print(df.info())
print('\n\ndescribe() ---------------------------')
print(df.describe())
print('\n\nshape & size ---------------------------')
print(df.shape)
print(df.size)
print('\n\ndtypes() ---------------------------')
print(df.dtypes)
head() ---------------------------
Rank Title Studio Gross Year
0 1 Avengers: Endgame Buena Vista $2,796.30 2019
1 2 Avatar Fox $2,789.70 2009
2 3 Titanic Paramount $2,187.50 1997
3 4 Star Wars: The Force Awakens Buena Vista $2,068.20 2015
4 5 Avengers: Infinity War Buena Vista $2,048.40 2018
tail() ---------------------------
Rank Title Studio Gross Year
777 778 Yogi Bear Warner Brothers $201.60 2010
778 779 Garfield: The Movie Fox $200.80 2004
779 780 Cats & Dogs Warner Brothers $200.70 2001
780 781 The Hunt for Red October Paramount $200.50 1990
781 782 Valkyrie MGM $200.30 2008
info() ---------------------------
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 782 entries, 0 to 781
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Rank 782 non-null int64
1 Title 782 non-null object
2 Studio 782 non-null object
3 Gross 782 non-null object
4 Year 782 non-null int64
dtypes: int64(2), object(3)
memory usage: 30.7+ KB
None
describe() ---------------------------
Rank Year
count 782.000000 782.000000
mean 391.500000 2006.620205
std 225.888247 10.026227
min 1.000000 1939.000000
25% 196.250000 2001.000000
50% 391.500000 2009.000000
75% 586.750000 2014.000000
max 782.000000 2019.000000
shape & size ---------------------------
(782, 5)
3910
dtypes() ---------------------------
Rank int64
Title object
Studio object
Gross object
Year int64
dtype: object
2. DataFrame 조작
- iloc[ ]: 숫자 인덱스로 모든 시리즈의 값들을 추출할때 (주의!: ( )괄호가 아닌 [ ] 이다.)
df = pd.read_csv('data/movies.csv', index_col="Title")
print(df.iloc[2])
------------
Rank 3
Studio Paramount
Gross $2,187.50
Year 1997
Name: Titanic, dtype: object
- loc[ ]: 이름 인덱스로 시리즈 값 추출 (주의!: ( )괄호가 아닌 [ ] 이다.)
df = pd.read_csv('data/movies.csv', index_col="Title")
print(df.loc['The Godfather'])
----------------
Rank 604
Studio Paramount
Gross $245.10
Year 1972
Name: The Godfather, dtype: object
- sort_index(): 예를들어 인덱스를 Title로 했을때 이러한 경우 영화제목을 알파벳 순서로 정렬하는 경우에 유용하다.
df = pd.read_csv('data/movies.csv', index_col="Title")
sorted_df = df.sort_index()
print(sorted_df)
---------------
Rank Studio Gross Year
Title
10,000 B.C. 536 Warner Brothers $269.80 2008
101 Dalmatians 708 Buena Vista $215.90 1961
101 Dalmatians 425 Buena Vista $320.70 1996
2 Fast 2 Furious 632 Universal $236.40 2003
2012 93 Sony $769.70 2009
... ... ... ... ...
Yogi Bear 778 Warner Brothers $201.60 2010
You've Got Mail 582 Warner Brothers $250.80 1998
Your Name. 356 FUN $358.00 2017
Zootopia 37 Buena Vista $1,023.80 2016
xXx: The Return of Xander Cage 385 Paramount $346.10 2017
sorted_df = df.sort_index(ascending=False)
- sort_values(by=["...", "...", ...]: 여러 기준으로 정렬
# 최신 영화 기준으로, 알파벳 영화 제목으로 정렬할때
sorted_df = df.sort_values(by=['Year', 'Title'], ascending=[False, True])
print(sorted_df)
--------------
Rank Studio Gross Year
Title
Aladdin 59 Buena Vista $880.20 2019
Alita: Battle Angel 286 Fox $404.90 2019
Avengers: Endgame 1 Buena Vista $2,796.30 2019
Captain Marvel 22 Buena Vista $1,128.30 2019
Dark Phoenix 603 Fox $245.10 2019
... ... ... ... ...
The Godfather 604 Paramount $245.10 1972
The Jungle Book 755 Buena Vista $205.80 1967
101 Dalmatians 708 Buena Vista $215.90 1961
Bambi 540 RKO $267.40 1942
Gone with the Wind 288 MGM $402.40 1939
[782 rows x 4 columns]
참고로, Title이 있는데도 4 columns로 나온다. 이것은 Title Series를 Index로 삼는순간 데이터가 아닌 index로 여기는 것이다. minor해 보일수 있지만 매우 중요한 개념이다. 즉, 데이터를 다룰때에 어떤 것을 데이터로 삼을지, 어떤 것을 인덱스로 삼을지 잘 고려해야 한다.
- 필터링: 조건문을 활용해서 필터링할 수 있다. 여러가지 조건들을 and(&)와 or(|)로 결합할 수 있다.
filter = df['Year'] == 2000
df[filter]
------------------
Rank Studio Gross Year
Title
Mission: Impossible II 175 Paramount $546.40 2000
Gladiator 237 Dreamworks $460.60 2000
Cast Away 261 Fox $429.60 2000
What Women Want 321 Paramount $374.10 2000
Dinosaur 375 Buena Vista $349.80 2000
filter = df['Year'].between(2000, 2005)
df[filter]
------------------
Rank Studio Gross Year
Title
The Lord of the Rings: The Return of the King 24 New Line $1,119.90 2003
Harry Potter and the Sorcerer's Stone 40 Warner Brothers $975.10 2001
Finding Nemo 49 Buena Vista $940.30 2003
The Lord of the Rings: The Two Towers 52 New Line $926.00 2002
Shrek 2 53 Dreamworks $919.80 2004
... ... ... ... ...
King Arthur 765 Buena Vista $203.60 2004
Vanilla Sky 767 Paramount $203.40 2001
Fun with Dick and Jane 773 Sony $202.00 2005
Garfield: The Movie 779 Fox $200.80 2004
Cats & Dogs 780 Warner Brothers $200.70 2001
filter1 = df['Studio'] == 'Sony'
filter2 = df['Year'] == 2000
print(df[filter1 & filter2])
----------------
Rank Studio Gross Year
Title
Charlie's Angels 548 Sony $264.10 2000
Vertical Limit 710 Sony $215.70 2000
The Patriot 712 Sony $215.30 2000
Crouching Tiger, Hidden Dragon 724 Sony $213.50 2000
- 인덱스 필터링: 특별히 인덱스는 index 파라미터를 통해 다룰 수 있다.
예) 영화 제목을 소문자로 바꾸고 제목에 'dark'라는 단어가 있는 모든 영화를 찾을 경우
filter = df.index.str.lower().str.contains('dark')
df[filter]
------------------
Rank Studio Gross Year
Title
Transformers: Dark of the Moon 23 Paramount $1,123.80 2011
The Dark Knight Rises 27 Warner Brothers $1,084.90 2012
The Dark Knight 39 Warner Brothers $1,004.90 2008
Thor: The Dark World 132 Buena Vista $644.60 2013
Star Trek Into Darkness 232 Paramount $467.40 2013
Fifty Shades Darker 309 Universal $381.50 2017
Dark Shadows 600 Warner Brothers $245.50 2012
Dark Phoenix 603 Fox $245.10 2019
3. 그룹화 : Bucket
제일 처음에 Bucket 개념을 간단히 소개하였는데 Bucket은 다시한번 강조한다면 세로 열들의 데이터들이 모여진 데이터프레임안에서 특정 조건 또는 범위의 가로 줄의 값들을 담아내는 과정이라고 보면된다.
예를들어, 영화사별로 그룹핑을 한다는 것은 영화사라는 컬럼을 그룹핑하는 것이 아니라 영화사라는 컬럼이 갖고 있는 값들이 있을때 그 값별로 그룹을 짓는 것이다. 미묘한 관점의 차이인데 꼭 이해하기를 바란다.
studio = df.groupby('Studio')
print(studio['Year'].count())
----------------------------
Studio
Artisan 1
Buena Vista 125
CL 1
China Film Corporation 1
Columbia 5
- 그룹 정렬
studio = df.groupby('Studio')
sorted_studio = studio['Year'].count().sort_values(ascending=False)
print(sorted_studio)
---------------------------
Studio
Warner Brothers 132
Buena Vista 125
Fox 117
Universal 109
Sony 86
Paramount 76
Dreamworks 27
Lionsgate 21
New Line 16
...
- Tip! 가격 등의 텍스트를 숫자로 바꾸는 방법: 판다스는 숫자안에 콤마, 달러 등의 기호가 들어가면 텍스트로 저장하게 되기 때문에 계산을 시도하면 오류가 발생된다. 그렇기 때문에 아래와 같이 변경해주어야 한다.
df["Gross"] = (df["Gross"]
.str.replace("$", "")
.str.replace(",", "")
.astype(float)
)
print(df)
--------------------------------
Rank Studio Gross Year
Title
Avengers: Endgame 1 Buena Vista 2796.3 2019
Avatar 2 Fox 2789.7 2009
Titanic 3 Paramount 2187.5 1997
Star Wars: The Force Awakens 4 Buena Vista 2068.2 2015
Avengers: Infinity War 5 Buena Vista 2048.4 2018
... ... ... ... ...
Gross 시리즈가 숫자로 변경되었기 때문에 이제 그룹화하여 다양한 계산이 가능해진다.
df["Gross"] = (df["Gross"]
.str.replace("$", "")
.str.replace(",", "")
.astype(float)
)
studio = df.groupby('Studio')
studio['Gross'].sum().sort_values(ascending=False)
------------------------------
Studio
Buena Vista 73585.0
Warner Brothers 58643.8
Fox 50420.8
Universal 44302.3
Sony 32822.5
Paramount 32486.0
Dreamworks 12260.4
Lionsgate 10033.2
New Line 6584.8
------------------------------
studio['Gross'].mean().sort_values(ascending=False)
Studio
HC 870.300000
China Film Corporation 699.800000
Newmarket 611.900000
Buena Vista 588.680000
Lionsgate 477.771429
Dreamworks 454.088889
오늘은 가장 기본적이지만 중요한 개념과 기본 오퍼레이션에 대해 정리하였다. 다음시간에는 Series 객체에 대해서 더 자세히 알아보자.
댓글