Pandas2
📌 Groupby
- split -> apply -> combine
인덱스(key)가 같은 데이터들끼리 쪼갠다. mean, sum 등의 함수를 적용한다. 합친다.
df.groupby["Team"]["Points"].sum()
#묶음의 기준이 되는 칼럼 # 적용받는 칼럼 # 적용받는 연산
# Team 컬럼에서 같은 값 끼리 묶어 points 컬럼 값을 합해준다.
-
묶음의 기준이 여러개가 될 수도 있다. (hierarchical index) -> index가 여러 개 생김
h_index = df.groupby(["Team", "Year"])["Points"].sum()
h_index
인덱스가 Team, Year로 두 개 생긴 걸 확인할 수 있다.
level 1 : Team , level 2 : Year이라고 함
- unstack() : Group으로 묶여진 데이터를 matrix형태로 반환해줌
❗❗ 풀어줄 수 있는 방법 한 가지 더 : reset_index()
- swap_level을 하게 되면 level1에 해당하는 Team과 level 2에 해당하는 Year의 위치가 바뀌게 된다.
h_index.swaplevel()
#Year Team
#2014 Devils 863
#2015 Devils 673
#2014 Kings 741
#2016 Kings 756
#2017 Kings 788
#2014 Riders 876
#2015 Riders 789
#2016 Riders 694
#2017 Riders 690
#2014 Royals 701
#2015 Royals 804
# kings 812
#Name: Points, dtype: int64
❗ 데이터 타입은 ?? 데이터 프레임이 아니라 시리즈다.
📌 groupby2
- groupby에 의해 split 된 상태를 추출 가능함
- tuple 형태로 그룹의 key - value 값이 추출됨
grouped = df.groupby("Team")
for name, group in grouped:
print(name)
print(group)
#######################################3
Devils
Team Rank Year Points
2 Devils 2 2014 863
3 Devils 3 2015 673
Kings
Team Rank Year Points
4 Kings 3 2014 741
6 Kings 1 2016 756
7 Kings 1 2017 788
Riders
Team Rank Year Points
0 Riders 1 2014 876
1 Riders 2 2015 789
8 Riders 2 2016 694
11 Riders 2 2017 690
Royals
Team Rank Year Points
9 Royals 4 2014 701
10 Royals 1 2015 804
kings
Team Rank Year Points
5 kings 4 2015 812
grouped에 Team column으로 묶었을 때의 key : 컬럼 내 이름 , value : key에 해당하는 데이터 프레임 값들
grouped = df.groupby("Team")
grouped
#<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000026472971B48>
grouped는 generator 형태
- get_group : 특정 key 값을 가진 그룹의 정보만 추출 가능
- 데이터타입 : DataFrame
grouped.get_group("Devils")
📌 group에 apply할 수 있는 세가지 유형 : aggregation , transformation , filtration
- aggregation
grouped.agg(max)
❗❗주의할 점 ❗❗
grouped.arr(max)의 행과 grouped의 행은 다르다!!!
grouped.arr(max)의 행에는 team["devils"]에 해당하는 데이터에서 각각 컬럼에 해당하는 최댓값을 뽑아준다.
team["devils"]의 경우 아래 표를 보면 rank의 최댓값은 index3의 3 , year은 index3의 2015, points는 index2의 points로 각각의 최댓값을 한 행으로 써놓은게 grouped.arr(max)다.
- 각 컬럼별 기술 통계량 값이 출력됨
df.describe()
- transformation : 개별 데이터의 변환을 지원 , 요약된 정보 x -> 주로 scaling
score = lambda x: (x - x.mean()) / x.std()
grouped.transform(score)
lamda x : x를 사용하면 원래 값들을 볼 수 있다.
grouped만 하면 generator기때문엥 값이 보이지 않는데 lambda를 사용하면 된다 ㅎㅎ
score = lambda x: x
grouped.transform(score)
- filter : 특정 조건으로 데이터를 검색할 때 사용
- filter 안에는 boolean 조건이 존재해야됨
- len은 grouped된 dataframe 개수
df.groupby("Team").filter(lambda x: len(x) >= 3)
위 코드의 출력값은 어떻게 될까?
df를 Team에 의해 나누게 되면 아래와 같은 결과를 얻을 수 있다.
grouped 된 개수가 "Devils"는 2개 , 'Kings'는 4개 , 'Riders'는 4개 , 'Royals'는 2개이다.
len은 grouped 된 dataframe의 개수를 의미하므로 len>=3을 만족시키는 Team은 Kings와 Riders 뿐이다.
결국 아래와 같은 출력 값을 가지게 된다.
df.groupby("Team").filter(lambda x: x["Points"].max() > 850)
"Team"을 기준으로 DataFrame을 grouped 했을 때 , points 칼럼의 최댓값이 850 이상인 데이터들을 출력해달라는 얘기다.
각 그룹별로 points의 최댓값은 Devils : 863 , Kings : 812 , Riders : 876 , Royals : 804이다.
최댓값이 850 이상인 points들은 Devils와 Riders이므로 그에 해당 한느 값들이 출력된다.
df[df["Points"] > 800] 와의 차이점은 무엇일까?
df[df["Points"] > 850]
points가 850을 넘는 행만 추출이 된다.
즉 df.groupby("Team").filter(lambda x: x["Points"].max() > 850) 는 팀전이다. 같은 팀내에 850이 넘는 팀원이 한명이라도 있으면 다 같이 가는거다. df[df["Points"] > 850] 는 개인전
📌 CASE STUDY
df_phone.dtypes
#index int64
#date object
#duration float64
#item object
#month object
#network object
#network_type object
#dtype: object
df_phone이라는 데이터 프레임의 데이터 형식을 보면 date가 "object"인 걸 확인할 수 있다.
string으로 되어있다는 뜻인데 이것보다는 datetime이 더 선호된다.
오늘 배운 apply를 이용하여 바꿔보자!
import dateutil
df_phone["date"] = df_phone["date"].apply(dateutil.parser.parse, dayfirst=True)
#문자 -> 날짜 모듈 : dateutil.parser.parse
df_phone.dtypes
#index int64
#date datetime64[ns]
#duration float64
#item object
#month object
#network object
#network_type object
#dtype: object
df_phone의 "date"column에 string을 datatime형식으로 바꿔주는 dateutil.parser.parse를 apply해줬다.
dtypes을 찍어보면 object였던 것이 datetime64로 바뀐 걸 확인할 수 있다.
df_phone.groupby("month")["duration"].sum().plot()
month를 기준으로 나누어서 duration을 sum한 값을 plot그림으로 보여달라는 뜻이다.
즉, 월별 통화량의 합을 의미한다.
df_phone[df_phone["item"] == "call"].groupby("month")["duration"].sum().plot()
df_phone[df_phone["item"] == "data"].groupby("month")["duration"].sum().plot()
df_phone[df_phone["item"] == "sms"].groupby("month")["duration"].sum().plot()
데이터프레임에서 item 컬럼의 값이 call 인 행에 대해서 month를 기준으로 그룹을 만들고 통화량의 합을 출력.
이런식으로 item이 call인 행들에 대해 month를 기준으로 group을 묶었을 때의 결과를 볼 수 있다.
월별로 duration의 값들을 sum 해주면
나머지 item이 sms , data일 때도 같이 그림을 그려주면
df_phone.groupby(["month", "item"])["duration"].count().unstack().plot()
차근차근 살펴보면 level1 = month , levle2 = item으로 group을 나누고 duration에 대하여 개수를 세준다.
unstack을 이용하여 matrix 형태로 만들어준다.
plot을 그림형태로 나타내보자. item이라는 범례에 따라 x 축은 month , y축에는 data값이 써져있다.
df_phone.groupby("month", as_index=False).agg({"duration": "sum"})
month에 대해 그룹으로 나눈 후 duration에 대해 sum 한 값을 출력하라.
특이한 점은 원래 month를 기준으로 나눴기 때문에 month 값들이 인덱스가 된다.
as_index = false를 인자로 넘겨주면 , month값들인 인덱스가 아니라 또 하나의 컬럼이 된다.
df_phone.groupby("month", as_index=False).agg({"duration": "sum"})
as_index를 사용하지 않으면
df_phone.groupby("month").agg({"duration": "sum"})
그러면 이런 생각을 해볼수 있다. 꼭 agg까지 가야되나? 그냥 sum()해주면 안되나?
df_phone.groupby(["month"])["duration"].sum()
값 자체는 같지만 데이터 형식이 데이터프레임이냐 시리즈냐의 차이가 존재하는 거 같다.
df_phone.groupby(["month", "item"]).agg(
{
"duration": [min], # find the min, max, and sum of the duration column
"network_type": "count", # find the number of network type entries
"date": [min, "first", "nunique"],
}
) # get the min, first, and number of unique dates
자기 입맛에 맞춰 다양하게 구성할 수 있다.
month, item를 기준으로 group을 지어, duration에는 그룹 내 최솟값을 , network_type에는 그룹에 해당하는 network 개수를, date에는 최솟값, 첫값, 유니크한 값의 개수를 써준다.
grouped.rename(
columns={"min": "min_duration", "max": "max_duration", "mean": "mean_duration"}
)
min, max , mean이었던 컬럼명을 재할당해줄수도 있다.
grouped.add_prefix("duration_")
add_prefix로 말 그대로 컬럼명에 접두사를 고정해주는거다.
위 코드 같은 경우 모든 컬럼명 앞에 duration_이 붙게 된다.
📌Pivot table
- Index 축은 groupby와 동일, column에 추가로 labeling 값을 추가하여, value에 numeric type값을 arrgeration하는 형태
이런 건 코드로 이해하는 게 더 빠르다,.
df_phone.pivot_table(
values=["duration"],
index=[df_phone.month, df_phone.item],
columns=df_phone.network,
aggfunc="sum",
fill_value=0,
)
월별, 아이템을 기준으로 나누어서 폰-네트워크라는 컬럼별 duration의 값을 본다.
이 때 duration의 sum값이 value로 들어가게 되고 NaN값은 0으로 대체된다.
첫번째 줄만 해석을 해보자!
df_phone 이라는 데이터 프레임에서 월은 2014-11이고 , item은 call인 행들만 가져와서 보자.
그러면 duration값이 여러가지일 텐데 그 중 Meteor에 해당하는 행들만 가져온다.
그 행들의 duration 값들을 더한 게 바로 value가 된다.
df_movie.pivot_table(
["rating"],
index=df_movie.critic,
columns=df_movie.title,
aggfunc="sum",
fill_value=0,
)
📌 crosstab
- pivot과 큰 차이 없다고 하심.
pd.crosstab(
index=df_movie.critic,
columns=df_movie.title,
values=df_movie.rating,
aggfunc="sum",
).fillna(0)
📌 merge & concat
- merge : 두 개의 데이터를 하나의 기준으로 합침
pd.merge(df_a, df_b, on="subject_id")
df_a, df_b 두개의 데이터 프레임을 subject_id를 기준으로 합한다는 뜻이다.
두 데이터 프레임에서 subject_id가 겹치는 4,5,7,8에 대해서만 두 데이터 프레임을 수평으로 합쳐준다.
pd.merge(df_a, df_b, on="subject_id", how="left")
- how = left : 왼쪽 데이터 프레임을 기준으로 merge된다.
왼쪽 데이터 프레임의 subject_id값과 같으면 오른쪽 프레임이 합쳐지고 만약 없다면 NaN으로 채워진다.
- how = right : 위와 마찬가지로 오른쪽 데이터 프레임을 기준으로 merge된다
- how = outer : 우선 그냥 합친 후, 없는 값에 대해선는 NaN으로 채워준다.
* default 값은 inner 이다.
- Concat : 리스트 형태로 값을 붙혀준다. 수직,수평 합치는 방향을 결정할 수 있다.
df_new = pd.concat([df_a, df_b])
df_new
- axis를 인자로 주어 concat 하는 축을 결정할 수 있다.
df_new = pd.concat([df_a, df_b], axis=1)
df_new.reset_index()
📌perisistence
- data loading 시 db connectin 기능을 제공함 (sqlite 모듈 사용)
- XLS : openpyxls, XlsxWrite 설치
!conda install --y XlsxWriter
확률론 맛보기
중간에 쓴 게 날라가서 우울하다,,,,
📌 딥러닝에서 확률론이 필요한 이유
- 딥러닝은 확률론 기반의 기계학습 이론에 바탕을 두고 있다.
- 손실함수들(L2 loss , cross-entropy)의 작동원리를 이해하귀 위해서는 확률론을 알아야한다.
📌 이산확률변수와 연속확률변수
- 확률분포 D에 따라 이산형과 연속형으로 구분한다.
- 이산형 확률변수 : 확률변수가 가질 수 있는 경우의 수를 모두 고려해 모델링한다. \[P(X\in A) = \sum_{X\in A}{P(X=x)}\]
- 연속형 확률변수는 데이터 공간에서 정의된 확률변수의 밀도 위에서의 적분을 통해 모델링한다.\[P(X\in A) = \int P(x)dx\]
📌 확률분포와 데이터
- 데이터 공간을 X x Y라 표기하고 , D는 데이터 공간에서 데이터를 추출하는 분포이다.
- 데이터는 확률변수로 (x,y) ~ D라 표기
- 주변확률분포 $P_{x}(X)$는 X만에 대한 정보로 Y에 대한 정보는 주지 않는다.
그냥 p(x)는 y값과 무관하게 x들의 분포만을 얘기한다.
- 조건부 확률분포 P(x|y)는 데이터 공간에서 입력과 출력 사이의 관계를 모델링합니다.
P(x|y=1)은 y값이 1일때의 x들의 분포를 얘기한다.
- p(y|x) : 어떤 데이터 x가 들어왔을 때 출력이 y일 확률을 의미한다.
❗ 주변 확률 분포 & 결합 확률 분포 & 조건부 확률 분포
📌 조건부 확률과 기계학습
- 특징패턴 $\phi$ 는 딥러닝의 다층신경망을 사용하여 데이터로부터 추출한다.
📌 몬테카를로 샘플링
데이터들이 이루고 있는 확률분포를 알면 참 좋겠지만 , 모르는 경우가 대부분이다.
데이터들이 이루고 있는 확률분포를 모르는 경우, 기댓값 (= 적분값) 을 계산하기 위해 몬테카를로 샘플링 방법을 사용한다. 몬테카를로 기법은 무작위로 데이터를 추출해, 임의의 함수의 적분값에 기대하는 방법이다.
몬테카를로는 이산형, 연속형 상관없이 성립한다. 단. 서로 독립적이어야한다.
독립 추출만 보장된다면 대수의 법칙에 의해 수렴성을 보장한다.
어떤 함수 g를 [0,1] 사이에서 적분한다고 해보자.
\[\theta = \int_{0}^{1} g(u)du\]
확률변수 U가 균일분포를 이루고 있다면 f는 [0,1]에서 1이다.
\[f_{U}(u)=\left\{\begin{matrix} 1 & 0\leq u\leq 1 \\ 0 & o.w \end{matrix}\right.\]
그러므로 위의 식을 아래처럼 쓸 수 있다.
\[\theta =\int_{0}^{1}g(u)du = \int_{0}^{1}g(u)f_{U}(u))du = E(g(u))\]
U가 0~1 사이의 균일분포를 따르므로 g(u)도 확률변수이다.
s 즉 표본의 크기가 커질수록 우리가 원하는 평균값에 근사하게 된다.
velog.io/@luvoatiger/%EC%A0%81%EB%B6%84%EA%B0%92-%EA%B5%AC%ED%95%98%EA%B8%B0
\[f(x) = e^{-x^{2}}\] 을 [-1,1]에서 적분한다고 생각해보자.
\[x \sim U(-1,1)\] 이라고 가정하면 , \[p(x) = \frac{1}{2}\]가 된다.
\[E(g(u)) = \frac{1}{2}\int_{-1}^{1}e^{-x^{2}}dx \approx \frac{1}{N}\sum f(x)\]
\[\int_{-1}^{1}e^{-x^{2}}dx = \frac{2}{N}\sum f(x)\]
import numpy as np
def mc_int(fun, low, high, sample_size = 100 , repeat = 10):
int_len = np.abs(high-low)
stat = []
for _ in range(repeat):
x = np.random.uniform(low = low , high = high, size = sample_size)
fun_x = fun(x)
int_val = int_len * np.mean(fun_x)
stat.append(int_val)
return np.mean(stat) , np.std(stat)
def f_x(x):
return np.exp(-x**2)
print(mc_int(f_x , -1,1))
#(1.4849826054542428, 0.02681348401167507)
Further question : 몬테카를로 방법을 활용하여 원주율에 대한 근사값을 어떻게 구할 수 있을까요?
나는 반지름이 1이고 , y값이 0이상인 반원을 생각했다.
\[f(x) = \sqrt{1-x^{2}}\] 의 넓이를 구해준 후 2를 곱해주면 반지름이 1짜리인 원의 넓이 pi가 된다.
몬테카를로 방법을 활용해서 원의 넓이를 구해보면 sample size = 100일때 10번을 반복하면
import numpy as np
def mc_int(fun, low, high, sample_size = 100 , repeat = 10):
int_len = np.abs(high-low)
stat = []
for _ in range(repeat):
x = np.random.uniform(low = low , high = high, size = sample_size)
fun_x = fun(x)
int_val = int_len * np.mean(fun_x)
stat.append(int_val)
return 2 * np.mean(stat)
def f_x(x):
return np.sqrt(1-x*x)
print(mc_int(f_x , -1,1))
# 3.116922701034716
sample size와 repeat을 더 늘리면 더욱 원주율에 가까워진다.
import numpy as np
def mc_int(fun, low, high, sample_size = 1000 , repeat = 100):
int_len = np.abs(high-low)
stat = []
for _ in range(repeat):
x = np.random.uniform(low = low , high = high, size = sample_size)
fun_x = fun(x)
int_val = int_len * np.mean(fun_x)
stat.append(int_val)
return 2 * np.mean(stat)
def f_x(x):
return np.sqrt(1-x*x)
print(mc_int(f_x , -1,1))
# 3.144156778735864
피어세션
백준 17212번 달나라 토끼를 위한 구매대금 지불 도우미
coin = [1,2,5,7]
n = int(input())
cost = [100000] * (n+1)
cost[0] = 0
for i in coin: #동전의 값
for j in range(1,n+1):
if j >= i : cost[j] = min(cost[j] , cost[j-i] + 1 )
print(cost[n])
dp = [[0 for _ in range(2)] for _ in range(91)]
dp[1][0] = 0
dp[1][1] = 1
n = int(input())
for i in range(2,n+1):
dp[i][0] = dp[i-1][0] + dp[i-1][1]
dp[i][1] = dp[i-1][0]
print(dp[n][0] + dp[n][1])
😁 평소 피어세션에서 수업내용 얘기하실 거 있냐고 물어보면 사람들이 아무말도 안하는데, 오늘 희준님의 아무것도 모르겠다는 커밍아웃(?)덕분에 희준님 뿐만이 아니라 서로 편하게 이해안되는 거 얘기하고 알려줄 수 있게 되었다. 서로 mbti도 맞추면서 한층 더 친해졌다 하ㅏ하 이런 캠프를 할 때마다 느끼는 거지만 조원들은 참 큰 힘이 되는 거 같다.
➕ 기술부채
지엽적인 거에 매몰되고 하나가 안되면 전체를 다 스탑해버리는 나한테 조교님이 기술부채라는 게 있다고 알려주셨다...ㅋㅋㅋㅋㅋㅋㅋㅋ해결되어야할 문제들을 뒤로 미루고 일단 해결하는 시점을 당기는 걸로, 깊게 오래 파기보다는 일단 얕게라도 한 번 끝내라는 말씀이신 거 같다.
생각해보면 나도 학원에서 일할 때 애들한테 일단 한바퀴 돌려! 이래놓고서 나는 정작 그렇게 안하니까 웃긴다.
앞으로는 충분히 고민해도 잘 안된다면 기술부채로 남겨두고 공부를 더 하고 와서 다시 되돌아보는 요행을 부려보자
'Naver Ai Boostcamp' 카테고리의 다른 글
[DAY 11] 딥러닝 기초 (0) | 2021.02.02 |
---|---|
[DAY 10] 시각화 / 통계학 (0) | 2021.01.30 |
[DAY 8] Pandas I / 딥러닝 학습방법 이해하기 (0) | 2021.01.27 |
[DAY 7] 경사하강법 (0) | 2021.01.26 |
[DAY 6] Numpy / 벡터 / 행렬 (0) | 2021.01.26 |