코딩하는 해맑은 거북이

인공지능(AI) 기초 다지기 (9) 본문

AI

인공지능(AI) 기초 다지기 (9)

#CJE 2023. 3. 6.
본 게시물의 내용은 '인공지능(AI) 기초 다지기(부스트코스)' 강의를 듣고 작성하였다.
해당 글은 4-2.  Pandas II / 확률론 맛보기 2가지 파트를 다룬다.
1. Pandas II 
2. 확률론 맛보기

 

1. Pandas II

Groupby I

▶ Groupby

  • df.groupby(묶음의 기준이 되는 컬럼)[적용받는 컬럼].적용받는연산()

 

- SQL groupby 명령어와 같음

- split → apply → combine

- 과정을 거쳐 연산함

 

# 예제 데이터
ipl_data = {'Team': ['Riders', 'Riders', 'Devils', 'Devils', 'Kings',
         'kings', 'Kings', 'Kings', 'Riders', 'Royals', 'Royals', 'Riders'],
         'Rank': [1, 2, 2, 3, 3,4 ,1 ,1,2 , 4,1,2],
         'Year': [2014,2015,2014,2015,2014,2015,2016,2017,2016,2014,2015,2017],
         'Points':[876,789,863,673,741,812,756,788,694,701,804,690]}

df = pd.DataFrame(ipl_data)
df

df.groupby("Team")["Points"].sum()

df.groupby("Team")["Points"].mean()

 

 

▶ Hierarchical index

- Groupby 명령의 결과물도 결국은 dataframe
- 두 개의 column으로 groupby를 할 경우, index가 두 개 생성된다.

 

- 한 개 이상의 column을 묶을 수 있음. 이때 2개의 index가 구성된 것을 Hierarchical index라고 부른다.

h_index = df.groupby(["Team", "Year"])["Points"].sum()
h_index

h_index.index

h_index["Devils":"Kings"]

 

 

- unstack()

Group으로 묶어진 데이터를 matrix 형태로 전환해줌

h_index.unstack()

h_index.unstack().stack()	# stack() 함수로 되돌릴수도 있음

 

- reset_index()

index를 없애주면서 풀어서 보여주는 함수

h_index.reset_index()	# index를 없애주면서 풀어서 보여준다.

 

- swaplevel()

index level을 변경할 수 있음, 아래의 예제에서 "Year"과 "Team"의 위치가 바뀐 것을 볼 수 있다.

h_index.swaplevel()

sort_index(level=0) 함수를 통해 "Year" index를 기준으로 sort 할 수 있다.

h_index.swaplevel().sort_index(level=0)

 

- sort_values()

연산된 값을 기준으로 정렬해서 보여준다.

h_index.sort_values()

 

Q. h_index의 타입은? Series

index가 2개 있다고해서 DF가 아니라 Series이다.

type(h_index)

 

- operations

index level을 기준으로 기본 연산 수행 가능하다.

h_index.sum(level=0)

h_index.sum(level=1)

 

 

 

Groupby II

 grouped

Groupby에 의해 split된 상태를 추출 가능하다.

→ Tuple 형태로 그룹의 key, value 값이 추출된다.

grouped = df.groupby("Team")
for name,group in grouped:
    print (name)
    print (group)

 

Q. group의 타입은? DataFrame

type(group)

 

특정 key값을 가진 그룹의 정보만 추출 가능 : get_group()

grouped.get_group("Devils")

 

* 추출된 group 정보에는 세 가지 유형의 apply가 가능함
- Aggregation: 요약된 통계정보를 추출해 줌
- Transformation: 해당 정보를 변환해줌
- Filtration: 특정 정보를 제거 하여 보여주는 필터링 기능

 

 

Aggregation

column 별로 연산을 해주되, group별로 데이터를 출력해준다.

grouped.agg(sum)

grouped.agg(max)

import numpy as np
grouped.agg(np.mean)

 

특정 column에 여러개의  function을 apply 할 수 도 있음

grouped['Points'].agg([np.sum, np.mean, np.std])

 

 transformation

Aggregation과 달리 key 값 별로 요약된 정보가 아니다!

개별 데이터의 변환을 지원한다.

transform : grouped된 상태에서 모든 값을 다 지정해주는 함수이다.

단, max나 min 처럼 Series 데이터에 적용되는 데이터들은 key값을 기준으로  Grouped된 데이터 기준

df

score = lambda x: (x.max())
grouped.transform(score)

 

score = lambda x: (x - x.mean()) / x.std()
grouped.transform(score)

 

filter

특정 조건으로 데이터를 검색할 때 사용한다.

df["Team"].value_counts()

df.groupby('Team').filter(lambda x: len(x) >= 3)	# 위의 결과로 봤을때 3이상 인 건 Riders, Kings

df.groupby('Team').filter(lambda x: x["Points"].max() > 800)

 

 

 

Case Study

- 원래 통화량 데이터

df_phone = pd.read_csv("phone_data.csv")
df_phone.head()

df_phone.dtypes

 

- 시간과 데이터 종류가 정리된 통화량 데이터

# 문자 형태의 date를 datetime 타입으로 변경해주기
import dateutil
df_phone['date'] = df_phone['date'].apply(dateutil.parser.parse, dayfirst=True)
df_phone.head()

df_phone.dtypes

df_phone.groupby('month')['duration'].sum()

df_phone.groupby('month')['duration'].sum().plot()  # 월별 통화량 그래프

df_phone[df_phone['item'] == 'call'].groupby('month')['duration'].sum()

df_phone[df_phone['item'] == 'call'].groupby('month')['duration'].sum().plot()

df_phone.groupby(['month', 'item'])['duration'].count()

df_phone.groupby(['month', 'item'])['duration'].count().unstack().plot()

df_phone.groupby('month', as_index=False).agg({"duration": "sum"})
# as_index=False : 'month'를 index로 설정하지 않는다는 것.

df_phone.groupby('month').agg({"duration": "sum"})

df_phone.groupby('month').agg({"duration": "sum"}).reset_index()

df_phone.groupby(['month', 'item']).agg({'duration':sum,      # find the sum of the durations for each group
                                     'network_type': "count", # find the number of network type entries
                                     'date': 'first'})    # get the first date per group

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

grouped = df_phone.groupby('month').agg( {"duration" : [min, max, np.mean]})
grouped

grouped.columns = grouped.columns.droplevel(level=0)
grouped

# column 이름 변경
grouped.rename(columns={"min": "min_duration", "max": "max_duration", "mean": "mean_duration"})

grouped = df_phone.groupby('month').agg( {"duration" : [min, max, np.mean]})
grouped

grouped.columns = grouped.columns.droplevel(level=0)
grouped

# 앞에 duration을 붙여줘서 어떤 column과 연산을 했는지 알아보기 쉽게 해줌
grouped.add_prefix("duration_")

 

 

Pivot table & Crosstab

Pivot Table

- 우리가 excel에서 보던 것
- Index축은 groupby와 동일함
- Column에 추가로 labeling값을 추가하여, Value에 numerictype값을 aggregation하는 형태

df_phone = pd.read_csv("phone_data.csv")
df_phone['date'] = df_phone['date'].apply(dateutil.parser.parse, dayfirst=True)
df_phone.head()

df_phone.pivot_table(values=["duration"],
                     index=[df_phone.month,df_phone.item], 
                     columns=df_phone.network,
                     aggfunc="sum",
                     fill_value=0)

# 물론 groupby를 써도 비슷한 결과를 가져올 수 있음
df_phone.groupby(["month", "item", "network"])["duration"].sum().unstack()

 

 

 

Crosstab

- 특허 두 칼럼에 교차 빈도,비율,덧셈 등을 구할 때 사용
- Pivottable의 특수한 형태
- User-ItemRatingMatrix등을 만들 때 사용가능함

import numpy as np
df_movie = pd.read_csv("/content/drive/My Drive/movie_rating.csv")
df_movie.head()

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)

df_movie.groupby(["critic","title"]).agg({"rating":"first"}).unstack().fillna(0)

 

 

 

Merge & Concat

Merge

- SQL에서 많이 사용하는 Merge와 같은 기능
- 두 개의 데이터를 하나로 합침

raw_data = {
        'subject_id': ['1', '2', '3', '4', '5', '7', '8', '9', '10', '11'],
        'test_score': [51, 15, 15, 61, 16, 14, 15, 1, 61, 16]}
df_a = pd.DataFrame(raw_data, columns = ['subject_id', 'test_score'])
df_a

raw_data = {
        'subject_id': ['4', '5', '6', '7', '8'],
        'first_name': ['Billy', 'Brian', 'Bran', 'Bryce', 'Betty'], 
        'last_name': ['Bonder', 'Black', 'Balwner', 'Brice', 'Btisan']}
df_b = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name'])
df_b

 

  • 두 dataframe의 column이 같을 때 : pd.merge(df_a, df_b, on='subject_id')
pd.merge(df_a, df_b, on='subject_id')

 

 

  • 두 dataframe의 column이 다를 때 : pd.merge(df_a, df_b, left_on='subject_id', right_on='subject_id')
pd.merge(df_a, df_b, left_on='subject_id', right_on='subject_id')

 

 

- join method

 

 

- left join

pd.merge(df_a, df_b, on='subject_id', how='left')

 

- right join

pd.merge(df_a, df_b, on='subject_id', how='right')

 

 

- full(outer) join

pd.merge(df_a, df_b, on='subject_id', how='outer')

 

 

- inner join

default 가 inner join 이다.

pd.merge(df_a, df_b, on='subject_id', how='inner')

 

 

- inner based join

pd.merge(df_a, df_b, right_index=True, left_index=True)

 

 

 

Concat

- 같은 형태의 데이터를 붙이는 연산작업

raw_data = {
        'subject_id': ['1', '2', '3', '4', '5'],
        'first_name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung'], 
        'last_name': ['Anderson', 'Ackerman', 'Ali', 'Aoni', 'Atiches']}
df_a = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name'])
df_a

raw_data = {
        'subject_id': ['4', '5', '6', '7', '8'],
        'first_name': ['Billy', 'Brian', 'Bran', 'Bryce', 'Betty'], 
        'last_name': ['Bonder', 'Black', 'Balwner', 'Brice', 'Btisan']}
df_b = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name'])
df_b

df_new = pd.concat([df_a, df_b])
df_new.reset_index(drop=True)

df_a.append(df_b)

df_new = pd.concat([df_a, df_b], axis=1)
df_new.reset_index(drop=True)

 

 

 


persistence

Database connection

- Dataloading시 db connection기능을 제공한다.

# Database 연결 코드
import sqlite3 #pymysql <- 설치

conn = sqlite3.connect("./data/flights.db")
cur = conn.cursor()
cur.execute("select * from airlines limit 5;")
results = cur.fetchall()
results
# db 연결 conn을 사용하여 dataframe 생성
df_airplines = pd.read_sql_query("select * from airlines;", conn)
df_airplines

 

 

XLS persistence

- Dataframe의 엑셀 추출 코드
- Xls 엔진으로 openpyxls 또는 XlsxWrite 사용

writer = pd.ExcelWriter('./data/df_routes.xlsx', engine='xlsxwriter')
df_routes.to_excel(writer, sheet_name='Sheet1')

 

 

Pickle persistence

- 가장 일반적인 python파일 persistence
- to_pickle,read_pickle 함수 사용

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

 

 


 

2. 확률론 맛보기

- 딥러닝에서 확률론이 왜 필요한가요?

  • 딥러닝은 확률론 기반의 기계학습 이론에 바탕을 두고 있다.
  • 기계학습에서 사용되는 손실함수(loss function)들의 작동 원리는 데이터 공간을 통계적으로 해석해서 유도하게 된다.
  • 회귀 분석에서 손실함수로 사용되는 L2-Norm은 예측오차의 분산을 가장 최소화하는 방향으로 학습을 유도한다.
  • 분류 문제에서 사용되는 교차엔트로피(cross-entropy)는 모델 예측의 불확실성을 최소화하는 방향으로 학습하도록 유도한다.
  • 분산 및 불확실성을 최소화하기 위해서는 측정하는 방법을 알아야 한다.
    • → 두 대상을 측정하는 방법을 통계학에서 제공하기 때문에 기계학습을 이해하려면 확률론의 기본 개념을 알아야 한다.

 

 

- 확률분포는 데이터의 초상화

  • 데이터공간을 X x Y라 표기하고 D는 데이터공간에서 데이터를 추출하는 분포이다.
  • 데이터는 확률변수로 (x, y) ~ D 라 표기한다.

여기선 데이터가 정답 레이블을 항상 가진 지도학습을 상정

파란색 점 : 데이터 공간상에서 관측한 데이터

데이터를 추출할 때 확률 변수를 사용하게 되고, 확률변수로 추출한 데이터의 분포를 D라고 한다.

 

  • 결합분포(Joint distribution) P(x, y)는 D를 모델링한다.

위의 그림에서 파란색 점들은 연속확률분포처럼 보이는 확률분포를 띄고있지만, 빨간색 칸막이로 나누게 되면 이산확률분포처럼 생각할 수 있다. 그럼 각각의 칸에 대해서 파란색 점의 갯수를 세면, 현재 주어진 데이터의 분포를 가지고 원래 확률 분포의 D를 모델링 할 수 있다.

 

  • P(x)는 입력 x에 대한 주변확률분포(Marginal distribution)로 y에 대한 정보를 주진 않는다.

주변확률분포 P(x)는 결합분포 P(x, y)에서 유도 가능하다.

 

각 x의 값에 따른 빈도

 

  • 조건부확률분포 P(x|y)는 데이터 공간에서 입력 x와 출력 y 사이의 관계를 모델링한다.

2개의 경우가 가능하다 - P(x|y) or P(y|x)

P(x|y)는 특정 클래스가 주어진 조건에서 데이터의 확률분포를 보여준다.

 

* y가 주어져 있는 상황에서 x에 대한 확률분포

y가 1인 경우에 대한 빈도수

 

 

 

cf) 이산확률변수 vs 연속확률변수

 

확률변수는 확률분포 D에 따라 이산형(discrete)연속형(continuous) 확률변수로 구분하게 된다.

→ 데이터공간 X x Y에 의해 결정 (X)

→ 확률분포 D에 의해 결정된다. (O)

 

이산형 확률변수확률변수가 가질 수 있는 경우의 수를 모두 고려하여 확률을 더해서 모델링한다.

확률질량함수 - 확률변수 X가 x의 값일 확률의 합

연속형 확률변수데이터 공간에서 정의된 확률변수의 밀도(density) 위에서의 적분을 통해 모델링한다.

확률밀도함수 - A상에서 P(x)를 적분 / P(x) : 누적확률분포의 변화률이다. 확률(X)

   * 모든 확률변수가 위의 2가지로만 구분되는 것은 아니다.

 

 

- 조건부확률과 기계학습

  • 조건부확률 P(y|x)는 입력변수 x에 대해 정답이 y일 확률을 의미한다.

     → 연속확률분포의 경우 P(y|x)는 확률이 아닌 밀도로 해석한다는 것에 주의!

  • 로지스틱 회귀에서 사용했던 선형모델과 소프트맥스 함수의 결합은 데이터에서 추출된 패턴을 기반으로 확률을 해석하는데 사용된다.
  • 분류 문제에서 softmax(WΦ+b)은 데이터 x로부터 추출된 특징패턴 Φ(x)과 가중치행렬 W을 통해 조건부확률 P(y|x)을 계산한다.

     → P(y|Φ(x)) 라고 써도 된다.

  • 회귀 문제의 경우 조건부기대값 E[y|x]을 추정한다.

     → 조건부기대값은 E||y - f(x)||2 을 최소화하는 함수 f(x)와 일치하기 때문에 종종 사용한다.

     → 통계적 모형에서 원하고자 하는 목적에 따라 통계추정이 달라질 수 있다. (중앙값 등)

  • 딥러닝은 다층신경망을 사용하여 데이터로부터 특징패턴 Φ을 추출한다

     → 특징패턴을 학습하기 위해 어떤 손실함수를 사용할지는 기계학습 문제와 모델에 의해 결정된다.

 

 

Q. 기대값이 뭔가요?

- 확률분포가 주어지면 데이터를 분석하는 데 사용 가능한 여러 종류의 통계적 범함수(statistical functional)를 계산할 수 있다. 
- 기대값(expectation)은 데이터를 대표하는 통계량이면서 동시에 확률분포를 통해 다른 통계적 범함수를 계산하는데 사용된다.

- 평균(mean)이랑 동일한 개념으로 사용할 수 있다. 그러나, 기계학습에서 사용하는 경우에는 훨씬 폭넒게 사용된다.

- 기대값을 이용해 분산, 첨도, 공분산 등 여러 통계량을 계산할 수 있다.

 

- 몬테카를로 샘플링

  • 기계학습의 많은 문제들은 확률분포를 명시적으로 모를 때가 대부분이다.
  • 확률분포를 모를 때 데이터를 이용하여 기대값을 계산하려면 몬테카를로 (Monte Carlo) 샘플링 방법을 사용해야 한다.

     → 몬테카를로는 이산형이든 연속형이든 상관없이 성립한다.

     → 중요한 것은 샘플링 하는 분포에서 독립적으로 항상 샘플링을 해줘야 몬테카를로 (Monte Carlo) 샘플링이 작동한다.

  • 몬테카를로 샘플링은 독립추출만 보장된다면 대수의 법칙(law of large number)에 의해 수렴성을 보장한다.

     → 이 방법을 통해 목표로 하는 기대값을 근사시킬 수 있다.

 

* 몬테카를로 예제 : 적분 계산하기

Q. 함수 \(f(x) = e^{-x^2}\)의 [-1, 1] 상에서 적분값을 어떻게 구할까?

f(x)의 적분을 해석적으로 구하는건 불가능하다.

균등분포이므로 구간 [-1, 1]의 길이는 2이므로 적분값을 2로 나누면 기대값을 계산하는 것과 같으므로 몬테카를로 방법을 사용할 수 있다.

1.49367&plusmn;0.0039 이므로 오차범위 안에 참값이 있다.

* 문제점 : 샘플사이즈가 적게되면 몬테카를로 방법으로 구해도 오차범위가 굉장히 커질 수 있고 참값에서 멀어질 수 있다.

그래서 적절한 샘플의 갯수를 조절해줘야 원하고자하는 적분값을 구할 수 있다.

Comments