1. 판다스(Pandas)
1.1 판다스(Pandas)란?
- 데이터 분석을 위한 사용이 쉽고 성능이 좋은(numpy로 작성됨) 오픈소스(공개된) python 라이브러리(파이썬으로만 사용가능)
- R과 Pandas의 차이점
- R보다 Pandas가 학습이 쉽습니다.
- R보다 Pandas가 성능이 좋습니다.
- R보다 Python은 활용할수 있는 분야가 많습니다.
- 크게 두가지 데이터 타입을 사용합니다.
- Series : index와 value로 이루어진 데이터 타입, Value는 동일한 데이터 타입을 가져야함
- DataFrame : index, column, value로 이루어진 데이터 타입(테이블형태) column 데이터는 Series, Series들이 모여서 DataFrame이 됨
1
import pandas as pd
- 판다스는 pd라는 약어로 자주 사용된다.
2. Series
2.1 Series란
- 동일한 데이터 타입의 값을 가짐
- value만 설정하면 index는 자동으로 0부터 설정됨
2.2 Series 기초
2.2.1 Series 생성
1
2
data = pd.Series(np.random.randint(10, size = 5))
data
1
2
3
4
5
6
0 6
1 4
2 6
3 4
4 0
dtype: int64
- pd.Series 메서드를 활용하여 Series를 생성 할수 있다.
- Series에서 S는 대문자이다.
2.2.2 Index 생성
1
2
data = pd.Series(np.random.randint(10, size=5), index=list('ABCDE'))
data
1
2
3
4
5
6
A 1
B 9
C 9
D 5
E 4
dtype: int64
- index 설정하는 법, Series 생성시 index = index 값으로 주면된다.
2.2.3 Index 활용
1
data.index, data.values
1
(Index(['A', 'B', 'C', 'D', 'E'], dtype='object'), array([5, 7, 0, 3, 5]))
- data.index 하면 index를 보여준다.
1
data['B']
1
9
- data에 index로 마스킹 하여 데이터 값을 확인 가능
1
data.B
1
9
- index로 데이터 확인
1
2
data['C'] = 10
data
1
2
3
4
5
6
A 5
B 7
C 10
D 3
E 5
dtype: int64
- index로 데이터를 불러와, 다른값(10)으로 변경도 가능함
1
data[['B','E']]
1
2
3
B 9
E 4
dtype: int64
- index를 여러개 지정하여 출력도 가능
2.2.4 Offset index
1
data[2]
1
9
- iterable[index]
1
data[1:4]
1
2
3
4
B 9
C 9
D 5
dtype: int64
- iterable[start:end]
1
data[0:4:2]
1
2
3
A 1
C 9
dtype: int64
- iterable[start : end: stride] ( stride는 보폭, 간격 이라고 생각하면 된다.)
1
data[::-1]
1
2
3
4
5
6
E 4
D 5
C 9
B 9
A 1
dtype: int64
- iterable[::-1] : 역순으로 출력
- Series도 Offset index를 사용가능함
- 문자열을 작성하게되면 각 문자마다 고유의 번호가 매겨지는데 이 번호를 오프셋이라 함,
- 오프셋을 이용하여 문자열에서 문자를 추출하는 것을 인덱싱이라 함
2.2.5 브로드 캐스팅
1
data * 10
1
2
3
4
5
6
A 10
B 90
C 90
D 50
E 40
dtype: int64
- 브로드캐스팅이란 배열에서 차원의 크기가 서로 다른 배열에서도 산술 연산을 가능하게 하는 원리
- Series도 브로드 캐스팅 개념이 있음
- data의 모든 value에 10을 곱해줄수 있음
2.3 Serise 연산
1
data
1
2
3
4
5
6
A 1
B 9
C 9
D 5
E 4
dtype: int64
1
2
data2 = pd.Series({'D' : 3, 'E' : 5, 'F' : 7})
data2
1
2
3
4
D 3
E 5
F 7
dtype: int64
1
2
result = data + data2
result
1
2
3
4
5
6
7
A NaN
B NaN
C NaN
D 8.0
E 9.0
F NaN
dtype: float64
- Series는 같은 index끼리 더해짐으로 양쪽애 같은 index가 없는 데이터는 NaN으로 나옴
2.4 Nan 데이터를 기존의 데이터에 넣어주는법
1
2
result[result.isnull()] = data
result
1
2
3
4
5
6
7
A 5.0
B 7.0
C 10.0
D 6.0
E 10.0
F NaN
dtype: float64
- isnull : 데이터가 NaN값이면 True를 반환하는 메서드
- result에 isnull 메서드를 사용하여 True로 만든 뒤 : result.isnull()
- result로 마스킹을 해주어 True값만 가져온다. result[result.isnull()] 하면 NaN값만 반환됨
- 위에서 반환된 NaN값은 data 값이라고 명시해주면 된다.
1
2
result[result.isnull()] = data2
result
1
2
3
4
5
6
7
A 5.0
B 7.0
C 10.0
D 6.0
E 10.0
F 7.0
dtype: float64
- 위와 같은 방법으로 data2의 F의 index 값도 넣어줌
3. DataFrame
3.1 DataFrame이란?
- 데이터 프레임은 여러개의 Series로 구성
- 같은 컬럼에 있는 value값은 같은 데이터 타입을 가짐
3.2 DataFrame 기초
3.2.1 데이터 프레임 생성 (1)
1
2
3
4
5
datas = {
'name' : ['dss', 'fcamp'],
'email' : ['dss@gmail.com', 'fcamp@daum.net']
}
datas
1
{'name': ['dss', 'fcamp'], 'email': ['dss@gmail.com', 'fcamp@daum.net']}
1
2
df = pd.DataFrame(datas)
df
name | ||
---|---|---|
0 | dss | dss@gmail.com |
1 | fcamp | fcamp@daum.net |
- 딕셔너리의 리스트 (딕셔너리의 value값에 리스트가 있음)
- 딕셔너리의 키값은 컬럼으로 잡히고, 벨류값은 데이터로 인식되게 됨
3.2.2 데이터 프레임 생성 (2)
1
2
3
4
5
datas =[
{'name' : 'dss', 'email' : 'dss@gmail.com'},
{'name': 'fcamp', 'email' : 'fcamp@daum.net'}
]
datas
1
2
[{'name': 'dss', 'email': 'dss@gmail.com'},
{'name': 'fcamp', 'email': 'fcamp@daum.net'}]
1
2
df = pd.DataFrame(datas)
df
name | ||
---|---|---|
0 | dss | dss@gmail.com |
1 | fcamp | fcamp@daum.net |
- 리스트 안에 딕셔너리
- 딕셔너리의 키값은 컬럼, 벨류값은 데이터 값
- 단점은 하나의 딕셔너리가 하나의 행으로 만들어져서 큰 데이터를 만들기에는 조금 번거로움
3.2.3 index
1
2
df = pd.DataFrame(datas, index = ['one', 'two'])
df
name | ||
---|---|---|
one | dss | dss@gmail.com |
two | fcamp | fcamp@daum.net |
- index = [] 값으로 추가 가능
1
df.index
1
Index(['one', 'two'], dtype='object')
- index값을 불러옴
3.2.4 Columns, Value
1
df.columns
1
Index(['name', 'email'], dtype='object')
- 데이터프레임.columns 메서드로 column들을 불러옴
- 해당 메서드는 생각보다 쓸모가 많음
1
df.values
1
2
array([['dss', 'dss@gmail.com'],
['fcamp', 'fcamp@daum.net']], dtype=object)
- 데이터프레임.value 메서드로 value값을 불러옴, 다만 데이터가 많을때는 그닥 추천하는 방법은 아님
3.3 Data Frame에서 데이터의 선택
3.3.1 Row 선택
1
2
3
4
5
6
7
8
datas = [
# 딕셔너리 1개는 1row, 딕셔너리의 key는 colum, value는 값
{"name": "dss", "email": "dss@gmail.com"},
# 딕셔너리 1개는 1row, 딕셔너리의 key는 colum, value는 값
{"name": "fcamp", "email": "fcamp@daum.net"}
]
df = pd.DataFrame(datas)
df
name | ||
---|---|---|
0 | dss | dss@gmail.com |
1 | fcamp | fcamp@daum.net |
- 리스트안에 딕셔너리 방식으로 데이터프레임 생성
1
df.loc[1]
1
2
3
name fcamp
email fcamp@daum.net
Name: 1, dtype: object
- row data 선택, series 데이터가 나옴
1
df.loc[1]['email']
1
'fcamp@daum.net'
- row data 선택, series 데이터가 나옴
- 뒤에 컬럼명을 마스킹 해주면 특정 컬럼만 가져올수 있음
1
2
df.loc[2] = {"name" : "andy", "email" : "andy@naver.com"}
df
name | ||
---|---|---|
0 | dss | dss@gmail.com |
1 | fcamp | fcamp@daum.net |
2 | andy | andy@naver.com |
- loc[2] index가 있으면 수정되며, 없으면 추가 됨
3.3.2 Column 선택
1
df['name']
1
2
3
4
0 dss
1 fcamp
2 andy
Name: name, dtype: object
- 데이터프레임[컬럼명] 으로 원하는 컬럼만 선택가능
- 시리즈 형식으로 출력됨
1
2
df['id'] = ''
df
name | id | ||
---|---|---|---|
0 | dss | dss@gmail.com | |
1 | fcamp | fcamp@daum.net | |
2 | andy | andy@naver.com |
- 데이터프레임[없는 컬럼명] = ‘’ 을 하면 column이 생성되고, 빈값(결측치 아님)이 들어감.
- 브로드 캐스팅되며 원하는 값이 있다면 넣어주어도 된다.
1
2
df['id'] = range(1,4)
df
name | id | ||
---|---|---|---|
0 | dss | dss@gmail.com | 1 |
1 | fcamp | fcamp@daum.net | 2 |
2 | andy | andy@naver.com | 3 |
- 없던 컬럼 값을 생성하면 추가됨
- 원래 있던 컬럼을 선택하면 수정
1
df.dtypes
1
2
3
4
name object
email object
id int64
dtype: object
- 데이터프레임.dtype으로 column별 데이터 타입 확인
- object는 데이터 타입의 상위 객체
3.3.3 Row, Column 선택
1
df.loc[[0, 2], ['email', 'id']]
id | ||
---|---|---|
0 | dss@gmail.com | 1 |
2 | andy@naver.com | 3 |
- 데이터프레임의 0번쨰, 2번째 행을 선택하고 그중 email과 id 컬럼만 선택하는 코드
- 2번 마스킹 해주어야 함
3.3.4 Column의 순서 변경
1
df[['id', 'name', 'email']]
id | name | ||
---|---|---|---|
0 | 1 | dss | dss@gmail.com |
1 | 2 | fcamp | fcamp@daum.net |
2 | 3 | andy | andy@naver.com |
- 두개 이상의 컬럼 선택시 리스트 데이터 타입으로, 쓴 순서대로 컬럼명이 정렬되어 나옴
3.5 데이터 미리보기
3.5.1 Head
1
df.head()
name | id | ||
---|---|---|---|
0 | dss | dss@gmail.com | 1 |
1 | fcamp | fcamp@daum.net | 2 |
2 | andy | andy@naver.com | 3 |
- 데이터프레임.head(n) 하면 앞에서 n개 만큼 데이터를 보여줌
- 디폴트 n은 5
3.5.2 Tail
1
df.tail()
name | id | ||
---|---|---|---|
0 | dss | dss@gmail.com | 1 |
1 | fcamp | fcamp@daum.net | 2 |
2 | andy | andy@naver.com | 3 |
- 데이터프레임.tail(n) 하면 뒤에서 n개 만큼 데이터를 보여줌
- 디폴트 n은 5
- 뒤의 데이터를 보기 때문에 해당 데이터가 몇개 인지 확인할수 있음
3.5.3 Shape
1
df.shape
1
(3, 3)
- shape메서드는 데이터의 크기 확인, 보통 분석시 merge나 join, duplicated(중복제거) 등을 사용할때 확인함
3.6 apply 함수
1
2
3
4
def domain(email):
return email.split('@')[1].split('.')[0]
domain(df.loc[0]['email'])
1
'gmail'
- email에서 도메인만 찾는 함수를 작성
1
2
df['domain'] = df['email'].apply(domain)
df
name | id | domain | ||
---|---|---|---|---|
0 | dss | dss@gmail.com | 1 | gmail |
1 | fcamp | fcamp@daum.net | 2 | daum |
2 | andy | andy@naver.com | 3 | naver |
- map 함수와 비슷한 역할이며, apply를 사용하여 각 행에 함수를 적용함
- 위의 코드는 email 컬럼에서 메일의 도메인만 가져와서 새로운 domain 컬럼을 생성하는 코드임
3.7 Append
1
2
3
from makedata import *
df1 = pd.DataFrame(make_data(5))
df2 = pd.DataFrame(make_data(5))
- makedata는 age와 name을 랜덤하게 생성해주는 모듈
- 따로 만든것이므로, 실제 파이썬에서 제공되는 모듈은 아님
1
2
df3 = df1.append(df2)
df3
Age | Name | |
---|---|---|
0 | 28 | Alan |
1 | 29 | Anchal |
2 | 35 | Anchal |
3 | 32 | Billy |
4 | 25 | Arnold |
0 | 37 | Jin |
1 | 34 | Alvin |
2 | 21 | Andrew |
3 | 28 | Arnold |
4 | 32 | Anthony |
- append 메서드를 활용하여 데이터 프레임 합치기
- df1.append(df2)를 하면 df1 아래에 df2가 합쳐지게 된다.
- offset index사용 가능
3.8 Reset_index
1
df3.reset_index()
index | Age | Name | |
---|---|---|---|
0 | 0 | 28 | Alan |
1 | 1 | 29 | Anchal |
2 | 2 | 35 | Anchal |
3 | 3 | 32 | Billy |
4 | 4 | 25 | Arnold |
5 | 0 | 37 | Jin |
6 | 1 | 34 | Alvin |
7 | 2 | 21 | Andrew |
8 | 3 | 28 | Arnold |
9 | 4 | 32 | Anthony |
- reset_index 메서드를 사용하여 인덱스 재정렬
- 기존에 있던 index가 컬럼으로 바뀌면서 새로운 컬럼으로 생성이됨
1
df3.reset_index(drop = True)
Age | Name | |
---|---|---|
0 | 28 | Alan |
1 | 29 | Anchal |
2 | 35 | Anchal |
3 | 32 | Billy |
4 | 25 | Arnold |
5 | 37 | Jin |
6 | 34 | Alvin |
7 | 21 | Andrew |
8 | 28 | Arnold |
9 | 32 | Anthony |
- drop = True 옵션을 주어 기존의 index를 컬럼으로 따로 저장하지 않음
1
df3
Age | Name | |
---|---|---|
0 | 28 | Alan |
1 | 29 | Anchal |
2 | 35 | Anchal |
3 | 32 | Billy |
4 | 25 | Arnold |
0 | 37 | Jin |
1 | 34 | Alvin |
2 | 21 | Andrew |
3 | 28 | Arnold |
4 | 32 | Anthony |
- 하지만 자동으로 저장이 되진 않음
- 자세히 보면 index가 그대로 0123401234 인것임을 볼수있음 저장이 안된것
1
2
df3.reset_index(drop = True, inplace= True)
df3
Age | Name | |
---|---|---|
0 | 28 | Alan |
1 | 29 | Anchal |
2 | 35 | Anchal |
3 | 32 | Billy |
4 | 25 | Arnold |
5 | 37 | Jin |
6 | 34 | Alvin |
7 | 21 | Andrew |
8 | 28 | Arnold |
9 | 32 | Anthony |
- 저장을 위해 Inplace = True 옵션을 주어야함
1
2
df3 = df1.append(df2, ignore_index= True)
df3
Age | Name | |
---|---|---|
0 | 28 | Alan |
1 | 29 | Anchal |
2 | 35 | Anchal |
3 | 32 | Billy |
4 | 25 | Arnold |
5 | 37 | Jin |
6 | 34 | Alvin |
7 | 21 | Andrew |
8 | 28 | Arnold |
9 | 32 | Anthony |
- reset_index를 사용하지 않고 append로 데이터 프레임을 합칠때 ignore_index = True의 옵션을 주어 index를 생성할수 있음
3.9 Concat
1
2
df3 = pd.concat([df1, df2])
df3
Age | Name | |
---|---|---|
0 | 28 | Alan |
1 | 29 | Anchal |
2 | 35 | Anchal |
3 | 32 | Billy |
4 | 25 | Arnold |
0 | 37 | Jin |
1 | 34 | Alvin |
2 | 21 | Andrew |
3 | 28 | Arnold |
4 | 32 | Anthony |
- row나 column으로 데이터 프레임을 합칠때 사용
- 위의 코드는 row로 합쳐지는 것(디폴트)
- append보다 기능이 더 많음
1
2
df3 = pd.concat([df1, df2]).reset_index(drop=True)
df3
Age | Name | |
---|---|---|
0 | 28 | Alan |
1 | 29 | Anchal |
2 | 35 | Anchal |
3 | 32 | Billy |
4 | 25 | Arnold |
5 | 37 | Jin |
6 | 34 | Alvin |
7 | 21 | Andrew |
8 | 28 | Arnold |
9 | 32 | Anthony |
- concat뒤에 .reset_index를 사용하여 바로 index를 재설정 할수 있음
1
pd.concat([df3, df1], axis = 1)
Age | Name | Age | Name | |
---|---|---|---|---|
0 | 28 | Alan | 28.0 | Alan |
1 | 29 | Anchal | 29.0 | Anchal |
2 | 35 | Anchal | 35.0 | Anchal |
3 | 32 | Billy | 32.0 | Billy |
4 | 25 | Arnold | 25.0 | Arnold |
5 | 37 | Jin | NaN | NaN |
6 | 34 | Alvin | NaN | NaN |
7 | 21 | Andrew | NaN | NaN |
8 | 28 | Arnold | NaN | NaN |
9 | 32 | Anthony | NaN | NaN |
- Column에 추가 하는 방법은 axis = 1 옵션을 주면됨
- 위의 경우엔 outer로 join되어 5 ~ 9 index는 Nan값이 나옴
1
pd.concat([df3, df1], axis = 1, join='inner')
Age | Name | Age | Name | |
---|---|---|---|---|
0 | 24 | Billy | 24 | Billy |
1 | 35 | Alan | 35 | Alan |
2 | 37 | Alan | 37 | Alan |
3 | 36 | Arnold | 36 | Arnold |
4 | 29 | Alex | 29 | Alex |
- join = inner 옵션을 주어 Nan 값은 join안되게 만들수 있음
3.10 Group by
1
2
df = pd.DataFrame(make_data())
df
Age | Name | |
---|---|---|
0 | 26 | Billy |
1 | 22 | Jin |
2 | 26 | Anthony |
3 | 25 | Andrew |
4 | 37 | Alan |
5 | 22 | Alex |
6 | 30 | Alan |
7 | 36 | Anthony |
8 | 27 | Adam |
9 | 20 | Billy |
- 실습용 데이터 생성
- 특정 컬럼의 중복되는 데이터를 합쳐서 새로운 데이터 프레임을 만드는 방법
- group by를 사용하면 name의 중복되는 데이터를 합쳐서 age의 평균, 중앙, 최소, 최대값 등을 볼수 있음
- Ex : 이름별 평균 나이
1
df.groupby('Name').size()
1
2
3
4
5
6
7
8
9
Name
Adam 1
Alan 2
Alex 1
Andrew 1
Anthony 2
Billy 2
Jin 1
dtype: int64
- groupby(‘Name’).size()로 이름의 중복을 제거하고 몇개가 중복이었는지 size를 (count)를 하는것
1
df.groupby("Name").size().reset_index()
Name | 0 | |
---|---|---|
0 | Adam | 1 |
1 | Alan | 2 |
2 | Alex | 1 |
3 | Andrew | 1 |
4 | Anthony | 2 |
5 | Billy | 2 |
6 | Jin | 1 |
- groupby size
- name은 index, 1,2등의 숫자는 value값으로, reset_index의 함수를 이용하여 DataFrame을 생성함
- reset_index의 기존 인덱스는 컬럼으로 재 생성하는 원리를 이용함
1
2
result_df = df.groupby("Name").size().reset_index(name = "count")
result_df
Name | count | |
---|---|---|
0 | Adam | 1 |
1 | Alan | 2 |
2 | Alex | 1 |
3 | Andrew | 1 |
4 | Anthony | 2 |
5 | Billy | 2 |
6 | Jin | 1 |
- Name 옆의 0 컬럼의 이름을 변경하기 위해 reset_index에서 name 옵션을 주었음
1
result_df.sort_values(['count'])
Name | count | |
---|---|---|
0 | Adam | 1 |
2 | Alex | 1 |
3 | Andrew | 1 |
6 | Jin | 1 |
1 | Alan | 2 |
4 | Anthony | 2 |
5 | Billy | 2 |
- sort_values : 설정한 컬럼으로 데이터 프레임을 정렬
- count를 오름차순으로 정렬(디폴트)
1
result_df.sort_values(['count'], ascending= False)
Name | count | |
---|---|---|
1 | Alex | 4 |
4 | Billy | 3 |
0 | Alan | 1 |
2 | Anthony | 1 |
3 | Arnold | 1 |
- 만일 내림차순으로 하고 싶다면, acsending = False 옵션을 주면됨
1
result_df.sort_values(['count'], ascending= False, inplace= True)
- 자동 저장이 안되기 때문에 inplace = True 옵션을 줌
1
2
result_df.reset_index(drop = True, inplace = True)
result_df
Name | count | |
---|---|---|
0 | Adam | 1 |
1 | Alan | 2 |
2 | Alex | 1 |
3 | Andrew | 1 |
4 | Anthony | 2 |
5 | Billy | 2 |
6 | Jin | 1 |
- index순서 정리 후 inplace로 저장
3.10.1 agg() 을 사용하면 데이터 프레임으로 결과가 출력됨
1
df.groupby('Name').agg('min').reset_index()
Name | Age | |
---|---|---|
0 | Alan | 36 |
1 | Alex | 23 |
2 | Anthony | 30 |
3 | Arnold | 20 |
4 | Billy | 36 |
- size(), min(), max(), mean() 등의 함수를 쓸 수 있음
3.11 Decsribe()
1
df.describe()
Age | |
---|---|
count | 10.000000 |
mean | 27.100000 |
std | 5.724218 |
min | 20.000000 |
25% | 22.750000 |
50% | 26.000000 |
75% | 29.250000 |
max | 37.000000 |
- 데이터의 기술통계치를 요약해서 보여주는 함수