※ 이 포스팅은 저자 'Kirthi Raman'의 도서 <Mastering Python Data Visualization> 을 공부하며 정리한 글입니다. 



Chapter 07. Bioinformatics, Genetics and Network Models (생물정보학, 유전학, 네트워크 모델)


이 장에서는 예제들을 다루기 위해 metaseq, NetworkX, matplotlib, Biopython, ETE toolkit 과 같은 라이브러리들을 사용한다.

Directed Graphs and Multigraphs (방향성 그래프와 멀티 그래프)

그래프와 방향성 그래프의 활용성을 알아보기 위해, 간단한 예를 생각해보자.


대학 캠퍼스 지역 내 서로 연결된 컴퓨터는 연결 그래프로 생각할 수 있고, 이 연결 안에서 각 컴퓨터는 노드(Node)나 정점(Vertex)이라 볼 수 있다.

연결된 길은 모서리이고, 어떤 경우 오직 한 방향 연결만 있다면 그것이 방향성 그래프이다.

또 다른 예로, 매우 엄격한 연방 네트워크는 밖에서부터 안으로 들어오는 어떤 연결도 허락하지 않을 것이나, 아마 반대로는 제약이 없을 것이다.


다음 간단한 그래프는 각 장소들 간의 거리를 보여준다.


앞의 예시에서 A부터 F까지 이름 붙여진 도시의 그래프는 방향성 그래프이고, 오른쪽 다른 그래프는 방향성이 없는 그래프이다.

방향성 그래프에서 화살표 방향이 양쪽으로 되어 있다면, 두 방향으로 갈 수 있는 길이 존재하는 것이다.

한편, 비방향성 그래프에서는 양쪽 방향 모두 가정한다. (오른쪽 그래프)


이러한 그래프들을 어떤 데이터 구조를 사용해 표현해야 할까?



#. Storing Graph Data (그래프 데이터 저장)

그래프 데이터는 보통 희소 행렬이나 인접 행렬로 나타내진다.

인접 행렬은 그래프가 V개의 정점(Vertex) 또는 노드(Node)를 갖는다고 가정했을 때, V2개 행을 갖는 행렬이다.


예를 들어, 앞에서 본 두 그래프들은 다음 표와 같은 인접 행렬이다.


 

25 

26 

 

 

 

 

85 

10 

 

26 

85 

 

 

10 

 

 

 

 

11 

 

 

 

88 

 

 

 

11 

88 


 

Chicago 

Boston 

New York 

Wash DC 

Miami 

Dallas 

Chicago 

1613 

 

1145 

 

 

Boston 

1613 

338 

725 

 

 

New York 

 

338 

383 

2145 

 

Wash DC 

1145 

725 

383 

1709 

2113 

Miami 

 

 

2145 

1709 

2161 

Dallas 

 

 

 

2113 

2161 


비방향성 그래프는 대칭적으로 저장공간의 반 정도를 사용하는 것으로 충분하다.

행렬의 빈 성분들은 거리에 관한 충분한 데이터가 있지 않음을 보여준다.


scipy에는 희소 행렬을 편리하게 다룰 수 있는 함수들이 존재한다.

다음 코드는 앞 그림의 첫 그래프에 해당한다.


import scipy.sparse as sparse


matrixA = sparse.lil_matrix((6,6))


matrixA = sparse.lil_matrix([

        [0,25,26,0,0,0],

        [0,0,85,5,10,0],

        [26,85,0,0,0,10],

        [0,0,0,0,0,11],

        [0,0,0,9,0,88],

        [0,0,0,11,88,0]

        ])


print matrixA


  (0, 1)        25

  (0, 2)        26

  (1, 2)        85

  (1, 3)        5

  (1, 4)        10

  (2, 0)        26

  (2, 1)        85

  (2, 5)        10

  (3, 5)        11

  (4, 3)        9

  (4, 5)        88

  (5, 3)        11

  (5, 4)        88


그래프를 보여주기 위해 사용할 수 있는 방대한 파이썬 패키지가 있다. 그 중 많이 사용되고 있는 TOP 3는 NetworkX, igraph, graph-tool 이다.



#. igraph

원래 igraph는 R 언어를 위해 만들어졌는데, 후에 파이썬 버전이 추가됐다.

igraph는 dimacs, dl, edgelist, graml, graphdb, gml, lgl, ncol, pajek 등 몇 가지 포맷들을 제공한다.


GraphML은 XML 기반 파일 포맷이며 큰 그래프에 사용될 수 있다.

NCOL 와 LGL 그래프 포멧은 Weighted Edge List를 가진 큰 그래프에 적합하다.

다른 대부분의 포맷들은 간단한 원문 포맷을 사용한다.

DL 파일 포맷만 igraph에 의해 모두 지원되며, 다른 포맷들은 부분적으로 지원한다.


igraph의 장점은, 편리하며 SVG 포맷으로 결과를 저장해 HTML 파일에 내장할 수 있다는 것이다.

(Anaconda Prompt에서 win-64(Microsoft Windows 64bit OS) 환경에서 다음 명령어를 통해 igraph를 설치할 수 있습니다.)


conda install -c vtraag python-igraph


이제, pajek 포맷을 포함하는 예제를 살펴보자. (http://vlado.fmf.uni-lj.si/pub/networks/pajek/ 참고)


import igraph


vertices = ["A", "B", "C", "D", "E"]


edges = [(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,1),

         (1,8),  (8,2),(2,4),(4,9),(9,5),(5,7),(7,0)]


graphStyle = { 'vertex_size': 20}

g = igraph.Graph(vertex_attrs={"label": vertices}, edges=edges, directed=True)

g.write_svg("simple_star.svg", width=500, height=300, **graphStyle)



다음은 파일로부터 그래프 데이터를 읽는 예제 코드이다.

(http://vlado.fmf.uni-lj.si/pub/networks/pajek/data/gphs.htm 에서 데이터 다운로드 가능)


from igraph import read  


g=read("Ragusa18.net",format="pajek")  

  

g.vs["color"]="#3d679d" 

g.es["color"]="red" 


graphStyle={ 'vertex_size': 12, 'margin': 6} 

#graphStyle["layout"]=g.layout("fr")  # optional


g.write_svg("ragusa_graph.svg", width=600, height=600,**graphStyle)



같은 데이터셋에서 다음 코드처럼 원형 모양 등의 레이아웃 옵션을 선택적으로 할당할 수 있다.


graphStyle["layout"]=g.layout("circle")




#. NetworkX

다음은 matplotlib을 통해 방향성 그래프를 만든 예제 코드이다


import matplotlib.pyplot as plt

import pylab

from pylab import rcParams


import networkx as nx


# set the graph display size as 10 by 10 inches

rcParams['figure.figsize'] = 10, 10


G = nx.DiGraph()


# Add the edges and weights

G.add_edges_from([('K', 'I'),('R','T'),('V','T')], weight=3)

G.add_edges_from([('T','K'),('T','H'),('T','H')], weight=4)


# these values to determine node colors

val_map = {'K': 1.5, 'I': 0.9, 'R': 0.6, 'T': 0.2}

values = [val_map.get(node, 1.0) for node in G.nodes()]


edge_labels=dict([((u,v,),d['weight'])

                 for u,v,d in G.edges(data=True)])


#set edge colors

red_edges = [('R','T'),('T','K')]

edge_colors = ['green' if not edge in red_edges else 'red' for edge in G.edges()]


pos=nx.spring_layout(G)


nx.draw_networkx_edges(G,pos,width=2.0,alpha=0.65)

nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)


nx.draw(G,pos, node_color = values, node_size=1500,

 edge_color=edge_colors, edge_cmap=plt.cm.Reds)


pylab.show()

nx.is_directed_acyclic_graph(G) 

.


이 그래프는 NetworkX를 사용해 그래프의 시각미와 모서리 굵기를 조절한 것이다.

방향성 그래프를 보여주는 여러 방법 중 NetworkX는 방향을 화살표 대신 끝을 두꺼운 막대로 표시한다.


추가로 최단 경로부터 연결수 분포, 클러스터링 계수까지 NetworkX는 다양한 그래프 분석 방법을 제공한다.
다음 코드는 최단 경로를 보여주는 간단한 예제 코드이다.

import networkx as nx


g = nx.Graph()

g.add_edge('m','i',weight=0.1)

g.add_edge('i','a',weight=1.5)

g.add_edge('m','a',weight=1.0)

g.add_edge('a','e',weight=0.75)

g.add_edge('e','h',weight=1.5) 

g.add_edge('a','h',weight=2.2)


nx.draw(g)


print nx.shortest_path(g,'i','h')


['i', 'a', 'h']


다음 예제는 레미제러블 소설에 등장하는 인물들의 관계를 나태낸다.

(https://gephi.org/datasets/lesmiserables.gml.zip 으로부터 데이터셋을 받을 수 있으며, GML 포맷 데이터로 되어있다.)


import networkx as nx

from pylab import rcParams

rcParams['figure.figsize'] = 12, 12


G = nx.read_gml('./lesmiserables.gml')

G8 = G.copy()

dn = nx.degree(G8)


#for n in G8.nodes():

#  if dn[n] <= 8:

#    G8.remove_node(n)


pos= nx.spring_layout(G8)

nx.draw(G8, node_size=10, edge_color='b', alpha=0.45, font_size=9, pos=pos)

labels = nx.draw_networkx_labels(G8, pos=pos)




#. The Planar Graph Test (평면 그래프 테스트)

평면 그래프는 교차하는 가장자리(Intersecting Edge) 없이 평면에 그려질 수 있는 그래프이다.

평면 그래프를 그리기 위해 정점으로부터 시작해 가장자리(edge)와 엣지(edge)를 그리고, 그려지는 면(face)들을 계속해서 추적해야 한다.


다음은 평면 그래프의 간단한 예이다.



오일러의 공식은 정점, 가장자리(edge), 면(face)들을 연결한다.

오일러에 따르면, 유한 연결 평면 그래프(Finite and Connected Planar Graph)가 교차하는 가장자리(edge) 없이 평면에 그려졌을때 다음 식이 성립한다.

v - e + f = 2 (v : 정점의 수, e = 가장자리 수, f = 면의 수)



#. The Directed Acyclic Graph Test (방향성 비순환 그래프 테스트)

방향성 비순환 그래프(DAG, Directed Acyclic Graph)란, 예로 정점 A로부터 B로의 엣지들은 특정 방향(A -> B or B -> A)을 지시하고 비순환성을 지닌다.

비순환 그래프는 순환이 없다. 다시말해, 사이클이 없는 것을 의미한다.


NetworkX 패키지의 is_directed_acyclic_graph(Graph)는 시각화의 맥락에서 그래프가 비순환인지 아닌지를 체크하는 방법을 제공한다.


import matplotlib.pyplot as plt

import pylab

from pylab import rcParams


import networkx as nx


# set the graph display size as 10 by 10 inches

rcParams['figure.figsize'] = 10, 10


G = nx.DiGraph()


# Add the edges and weights

G.add_edges_from([('K', 'I'),('R','T'),('V','T')], weight=3)

G.add_edges_from([('T','K'),('T','H'),('T','H')], weight=4)

# these values to determine node colors

val_map = {'K': 1.5, 'I': 0.9, 'R': 0.6, 'T': 0.2}

values = [val_map.get(node, 1.0) for node in G.nodes()]


edge_labels=dict([((u,v,),d['weight'])

                 for u,v,d in G.edges(data=True)])


#set edge colors

red_edges = [('R','T'),('T','K')]

edge_colors = ['green' if not edge in red_edges else 'red' for edge in G.edges()]


pos=nx.spring_layout(G)


nx.draw_networkx_edges(G,pos,width=2.0,alpha=0.65)

nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)


nx.draw(G,pos, node_color = values, node_size=1500,

 edge_color=edge_colors, edge_cmap=plt.cm.Reds)


pylab.show()


nx.is_directed_acyclic_graph(G) 


True




#. Maximum Flow and Minimum Cut (최대 플로우와 최소 컷)

'플로우 네트워크'는 소스로부터 목적지까지 방향성을 가진 그래프이며 각 엣지를 따라 할당된 용량(Capacity)이 주어진다.

최단 경로를 찾기 위해 방향성 그래프로 거리 지도를 모델링하는 것과 비슷하게, 플로우 네트워크로 방향성 그래프를 해석할 수 있다.

예시로는 파이프를 통해 흐르는 액체, 전기 네트워크를 통과하는 전류, 데이터 통신 네트워크를 통해 전송되는 데이터 등이다.



그래프 G의 엣지들은 엣지가 얼만큼의 플로우를 지원할 수 있는지에 대한 용량을 가지고 있다. 용량이 없다면 무한으로 가정한다.

위 그래프에서 플로우 네트워크 G의 최대 플로우는 4이다.


NetworkX 패키지의 maximum_flow_value(Graph, from, to)는 그래프의 최대 플로우를 계산한다.


import networkx as nx

G = nx.DiGraph()

G.add_edge('p','y', capacity=5.0)

G.add_edge('p','s', capacity=4.0)

G.add_edge('y','t', capacity=3.0)

G.add_edge('s','h', capacity=5.0)

G.add_edge('s','o', capacity=4.0)


flow_value = nx.maximum_flow_value(G, 'p', 'o')


print "Flow value", flow_value


Flow value 4.0


...

※ 이 포스팅은 저자 'Kirthi Raman'의 도서 <Mastering Python Data Visualization> 을 공부하며 정리한 글입니다. 



Chapter 06. Statistical and Machine Learning (통계 및 머신러닝)


최근 머신러닝은 인공지능에서 가장 중요한 부분이 됐다.
연산 속도 등 컴퓨팅 성능의 발전으로 인해, 머신러닝을 통해 인공지능 시스템을 구축할 수 있게 될 가능성이 매우 높아졌다.

Linear Regression (선형 회귀)

선형 회귀분석은 주어진 입력변수(X)와 반응변수(Y)간의 관계를 선형 관계식으로 모형화하는 것이다.

다음 주어진 데이터에 대해 선형 회귀분석을 실시. 목표 응답변수(target response variable, Y)는 acceptance 이다.



import pandas as pd

import statsmodels.formula.api as smf

from matplotlib import pyplot as plt


df = pd.read_csv('./sports.csv', index_col=0)

fig, axs = plt.subplots(1, 3, sharey=True)

df.plot(kind='scatter', x='sports', y='acceptance', ax=axs[0], figsize=(16, 8))

df.plot(kind='scatter', x='music', y='acceptance', ax=axs[1])

df.plot(kind='scatter', x='academic', y='acceptance', ax=axs[2])


# 적합된 모형을 생성

lm = smf.ols(formula='acceptance ~ music', data=df).fit()


X_new = pd.DataFrame({'music': [df.music.min(), df.music.max()]})

preds = lm.predict(X_new)


df.plot(kind='scatter', x='music', y='acceptance', figsize=(12,12), s=50)


plt.title("Linear Regression - Fitting Music vs Acceptance Rate", fontsize=20)

plt.xlabel("Music", fontsize=16)

plt.ylabel("Acceptance", fontsize=16)


# 최소제곱선 도식화

plt.plot(X_new, preds, c='red', linewidth=2)




선형 회귀분석을 사용하기 위한 많은 수학적 파이썬 라이브러리들이 있다.

주로 scikit-learn, seaborn, statsmodels, mlpy 들이 사용되고 기억할 만한 것들이다.

참고 : http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html




Decision Tree (의사결정나무)

날씨에 따라 야외활동을 하는 것이 좋은가 나쁜가의 예제를 살펴본다.


from sklearn.externals.six import StringIO

from sklearn import tree

import pydot 


X=[[1,1,1,0],[1,1,1,1],[2,1,1,0],[2,3,2,1],[1,2,1,0],[1,3,2,0],\

[3,2,1,0],[3,3,2,0],[3,3,2,1],[3,2,2,0],[1,2,2,1],[2,2,1,1],\

[2,1,2,0],[3,2,1,0]]  


Y=[0,0,1,1,0,1,1,1,0,1,1,1,1,0] 


clf = tree.DecisionTreeClassifier()

clf = clf.fit(X, Y)


dot_data = StringIO() 

tree.export_graphviz(clf, out_file=dot_data) 


graph = pydot.graph_from_dot_data(dot_data.getvalue()) 

graph.write_pdf("game.pdf")




Naive Bayes Classifier (나이브 베이즈 분류기)

나이브 베이즈 분류법의 선행으로 베이즈 정리를 이해할 필요가 있다.


#. 베이즈 정리 (The Bayes Theorem)

다음 그림처럼 모든 사람이 U라는 전체 공간에 속하고,

유방암에 걸린 사람들의 집합을 A, 표본 검사에서 유방암으로 진단 받은 사람들의 집합을 B라고 가정하면 A∩B의 교집합이 존재한다.



2개의 다른 공간에 주목할 필요가 있다.

(1) B - A∩B : 유방암 진단에서 양성 판정을 받았으나, 실제 유방암에 걸리지 않은 집단

(2) A - A∩B : 유방암 진단에서 음성 판정을 받았으나, 실제 유방암에 걸린 집단


여기서 우리가 알고 싶은 정보가, 양성 판정을 받은 사람이 실제로 유방암에 걸렸을 확률이라고 하자.

수학적으로 표현한다면, B(유방암 진단을 받음)가 주어졌을 때 A(실제 유방암에 걸림)인 조건부 확률이라고 할 수 있다.



(즉, B에 대한 정보가 있기 때문에 확률 계산의 전체 공간이 U에서 B로 좁혀지게 되는 것입니다.)


비슷하게, 암을 가지고 있는 사람에 대해 알고 있을 때 암진단 테스트가 양성 반응으로 나올 확률은 다음과 같다.



따라서, 베이즈 정리를 다음과 같이 유도할 수 있다.



이 베이즈 정리는 A와 B 사건에 대해 B가 일어날 확률이 0이 아닐 경우에 유용하다.



#. 나이브 베이즈 분류기 (Naive Bayes Classifier)

나이브 베이즈 분류 기법은 입력 자유도(변수의 개수)가 높을 때 사용하기 적절하다.

상대적으로 간단하지만, 좋은 성능을 나타낸다.

(참고 : http://scikit-learn.org/stable/modules/naive_bayes.html 및 http://sebastianraschka.com/Articles/2014_naive_bayes_1.html )


다음 예제를 살펴보자.


빨간색 : 유방암에 걸린 집단

파란색 : 양성 진단을 받은 집단

흰색    : 새로운 사람



이 데이터를 통해 우리가 알 수 있는 정보는 다음과 같다.




#. TextBlob 라이브러리를 활용한 나이브 베이즈 분류기

TextBlob은 문자처리를 위한 도구들의 모음이다.

또한, NLP(자연어 처리, Natural Language Processing)를 위한 API를 제공해 분류, 명사구 추출, 대화 일부분 태깅, 감정 분석 등을 할 수 있다.


아나콘다 프롬포트(Anaconda Prompt)에서 다음 명령어를 통해 TextBlob를 설치할 수 있습니다.

conda install -c conda-forge textblob


그 다음, 예제 분석을 위한 말뭉치(Corpus)를 다음과 같이 다운받을 수 있다. (이 또한 하나콘다 프롬포트에서 진행합니다.)


python -m textblob.download_corpora


TextBlob을 이용해 고유의 문자 분류기를 쉽게 만들 수 있다.

TextBlob 0.6.0 버전 기준으로 다음 분류기들을 사용할 수 있다.


- BaseClassifier

- DecisionTreeClassifier

- MaxEntClassifier

- NLTKClassifier

- NaiveBayesClassifier

- PositiveNaiveBayesClassifier


다음 예제는 NaiveBayesClassifier를 활용한 감성 분석이다.


from textblob.classifiers import NaiveBayesClassifier

from textblob.blob import TextBlob


train = [

    ('I like this new tv show.', 'pos'),

    ('This is a very exciting event!', 'pos'),

    ('I feel very good about after I workout.', 'pos'),

    ('This is my most accomplished work.', 'pos'),

    ("What an awesome country", 'pos'),

    ("They have horrible service", 'neg'),

    ('I do not like this new restaurant', 'neg'),

    ('I am tired of waiting for my new book.', 'neg'),

    ("I can't deal with my toothache", 'neg'),

    ("The fun events in costa rica were amazing",'pos'), 

    ('He is my worst boss!', 'neg'),

    ('People do have bad writing skills on facebook', 'neg')

]

test = [

    ('The beer was good.', 'pos'),

    ('I do not enjoy my job', 'neg'),

    ("I feel amazing!", 'pos'),

    ('Mark is a friend of mine.', 'pos'),

    ("I can't believe I was asked to do this.", 'neg')

]


cl = NaiveBayesClassifier(train)

print(cl.classify("The new movie was amazing."))  # "pos"

print(cl.classify("I don't like ther noodles."))   # "neg"


print "Test Results"

cl.update(test)


# Classify a TextBlob

blob = TextBlob("The food was good. But the service was horrible. "

                "My father was not pleased.", classifier=cl)

print(blob)

print(blob.classify())


for sentence in blob.sentences:

    print(sentence)

    print(sentence.classify())


# Compute accuracy

print("Accuracy: {0}".format(cl.accuracy(test)))


# Show 5 most informative features

cl.show_informative_features(10)




Viewing Positive Sentiments using Word Clouds (워드클라우드를 이용해 긍정적인 감정 분석)

워드클라우드는 문서에 대한 각 단어들의 빈도를 잘 표현하는 것으로 매우 유명하다.

단어의 등장 횟수에 따라 글자의 크기를 바꿔 시각화한다. 가장 자주 나타난 단어의 크기가 가장 크게 표현된다.


아나콘다 프롬포트(Anaconda Prompt)에서 다음 명령어를 통해 wordcloud 패키지를 설치할 수 있습니다.

conda install -c conda-forge wordcloud


다음 예제 코드에서 STOPWORDS 는 a, an, the, is, was, at, in 과 같은 분석적으로 의미 없는 단어들을 제외하기 위한 단어 모음이다.


from wordcloud import WordCloud, STOPWORDS

import matplotlib.pyplot as plt

from os import path


d = path.dirname("__file__")

text = open(path.join(d, './results.txt')).read()


wordcloud = WordCloud(

    #font_path='/Users/MacBook/kirthi/RemachineScript.ttf',

    stopwords=STOPWORDS,

    background_color='#222222',

    width=1000,

    height=800).generate(text)


# Open a plot of the generated image.

plt.figure(figsize=(13,13))


plt.imshow(wordcloud)

plt.axis("off")


plt.show()




#. K-근접 이웃 (K-nearest Neighbors, KNN)

KNN 분류법은 가장 이해하기 쉬운 분류 방법 중에 하나이며, 부분적으로 데이터 분포의 사전 정보가 적거나 없을 때 사용된다.


사과, 배, 그리고 바나나 분류에 대한 다음 데이터와 예제를 살펴보자.



import csv

import matplotlib.pyplot as plt


count=0

x=[]

y=[]

z=[]


with open('./fruits_data.csv', 'r') as csvf:

  reader = csv.reader(csvf, delimiter=',')

  for row in reader:

    if count > 0:

      x.append(row[0])

      y.append(row[1])

      if ( row[2] == 'Apple' ): z.append('r')

      elif ( row[2] == 'Pear' ): z.append('g')

      else: z.append('y')

    count += 1


plt.figure(figsize=(11,11))


recs=[]

classes=['Apples', 'Pear', 'Bananas']

class_colours = ['r','g','y']

plt.title("Apples, Bananas and Pear by Weight and Shape", fontsize=18)


plt.xlabel("Shape category number", fontsize=14)

plt.ylabel("Weight in ounces", fontsize=14)


plt.scatter(x,y,s=600,c=z)



위 사진은 주어진 데이터를 시각화 한 것이다.

( 빨강색 : 사과 / 초록색 : 배 / 노랑색 : 바나나 )


만약 종류를 알 수 없는 과일에 대한 정보가 있을 때, 그것을 예측하는 예제 코드는 다음과 같다.


from math import pow, sqrt


dist=[]


def determineFruit(xv, yv, threshold_radius):

  for i in range(1,len(x)):

    xdif=pow(float(x[i])-xv, 2)

    ydif=pow(float(y[i])-yv, 2)

    sqrtdist = sqrt(xdif+ydif)

    if ( xdif < threshold_radius and 

         ydif < threshold_radius and sqrtdist < threshold_radius):

      dist.append(sqrtdist)

    else:

      dist.append(99)


  pear_count=0

  apple_count=0

  banana_count=0


  for i in range(1,len(dist)):

      if dist[i] < threshold_radius:

        if z[i] == 'g': pear_count += 1

        if z[i] == 'r': apple_count += 1

        if z[i] == 'y': banana_count += 1


  if ( apple_count >= pear_count and apple_count >= banana_count ):

    return "apple"

  elif ( pear_count >= apple_count and pear_count >= banana_count):

    return "pear"

  elif ( banana_count >= apple_count and banana_count >= pear_count):

    return "banana"


dist=[]

determine = determineFruit(3.5,6.2, 1)

print determine


banana




Logistic Regression (로지스틱 회귀분석)

범주형 반응변수(Y=1 or 0)의 경우, 선형 회귀분석보다 시그모이드 함수를 활용하는 로지스틱 회귀분석이 더 적합하다.

왜냐하면, 입력변수와 계수의 곱의 합으로 구성된 선형모형은 그 범위가 ±∞ 이지만, 시그모이드 함수는 (0, 1) 이기 때문이다.


아래 수식은 p개의 입력변수에 대한 Y의 확률을 시그모이드 함수로 표현한 것이다.



파이썬에서 표준 시그모이드 함수를 그려보면, 왜 이 함수를 사용하는지 조금 더 쉽게 이해할 수 있다.


import matplotlib.pyplot as plt

import numpy as np


plt.title("Sigmoid Functions vs LineSpace")


x = np.linspace(-10,10,100)


y1 = 1.0 / (1.0+np.exp(-x))

plt.plot(x,y1,'r-',lw=2)


y2 = 1.0 / (1.0+np.exp(-x/2))

plt.plot(x,y2,'g-',lw=2)


y3 = 1.0 / (1.0+np.exp(-x/10))

plt.plot(x,y3,'b-',lw=2)


plt.xlabel("x")

plt.ylabel("y")



붉은색(1) --> 초록색(1/2) --> 파랑색(1/10) 순으로 x의 계수가 낮다는 점에 주목하자.

붉은색의 경우에 값이 커짐에 따라 y가 1일 확률이 급격하게 높아지지만, 파랑색의 경우에는 경사가 완만함을 알 수 있다.

또한 값이 항상 (0, 1) 범위에 있어 해당 범주에 속할 확률로 사용이 가능함을 알 수 있다.


이제, Kaggle에서 제공한 '타이타닉 생존자 예측' 위한 데이터셋을 예제로 로지스틱 회귀분석을 적용해보자.


import numpy as np

import pandas as pd

import sklearn.linear_model as lm

import sklearn.cross_validation as cv

import matplotlib.pyplot as plt


train = pd.read_csv('./titanic_train.csv')

test = pd.read_csv('./titanic_test.csv')

train[train.columns[[2,4,5,1]]].head()


   Pclass     Sex   Age  Survived

0       3    male  22.0         0

1       1  female  38.0         1

2       3  female  26.0         1

3       1  female  35.0         1

4       3    male  35.0         0


data = train[['Sex', 'Age', 'Pclass', 'Survived']].copy()

data['Sex'] = data['Sex'] == 'female'

data = data.dropna()


data_np = data.astype(np.int32).values

X = data_np[:,:-1]

y = data_np[:,-1]


female = X[:,0] == 1

survived = y == 1


# This vector contains the age of the passengers.

age = X[:,1]


# We compute a few histograms.

bins_ = np.arange(0, 121, 5)

S = {'male': np.histogram(age[survived & ~female], 

                          bins=bins_)[0],

     'female': np.histogram(age[survived & female], 

                            bins=bins_)[0]}

D = {'male': np.histogram(age[~survived & ~female], 

                          bins=bins_)[0],

     'female': np.histogram(age[~survived & female], 

                            bins=bins_)[0]}

bins = bins_[:-1]

plt.figure(figsize=(15,8))

for i, sex, color in zip((0, 1),('male', 'female'), ('#3345d0', '#cc3dc0')):

    plt.subplot(121 + i)

    plt.bar(bins, S[sex], bottom=D[sex], color=color,

            width=5, label='Survived')

    plt.bar(bins, D[sex], color='#aaaaff', width=5, label='Died', alpha=0.4)

    plt.xlim(0, 80)

    plt.grid(None)

    

    plt.title(sex + " Survived")

    plt.xlabel("Age (years)")

    plt.legend()

    

(X_train, X_test, y_train, y_test) = cv.train_test_split(X, y, test_size=.05)

print X_train, y_train


# Logistic Regression from linear_model

logreg = lm.LogisticRegression();

logreg.fit(X_train, y_train)

y_predicted = logreg.predict(X_test)


plt.figure(figsize=(15,8));

plt.imshow(np.vstack((y_test, y_predicted)),

           interpolation='none', cmap='bone');

plt.xticks([]); plt.yticks([]);

plt.title(("Actual and predicted survival outcomes on the test set"))


logreg.coef_

array([[ 2.40922883, -0.03177726, -1.13610297]])






Support Vector Machine (서포트 벡터 머신, SVM)

SVM은 수치형 또는 범주형 반응변수(Y) 모두 적용 가능한 지도학습 알고리즘으로서, 경험적으로 좋은 성능을 제공한다고 알려져있다.

생물정보학(Bioinformatics), 문자, ㅇ므성 인식 등의 여러 범위에서 성공적인 비선형(Non-linear) 모형의 확장 알고리즘으로 자리잡고 있다.

SVM은 계산이 복잡하지 않고 구현이 쉽다는 장점이 있으나, Underfitting의 경향이 있어 정확도가 낮을 수 있다는 단점이 있다.


다음은 scikit-learn(skilearn) 라이브러리를 활용한 파이썬 예제이다.


import numpy as np

from sklearn.svm import SVR

import matplotlib.pyplot as plt


X = np.sort(5 * np.random.rand(40, 1), axis=0)

y = (np.cos(X)+np.sin(X)).ravel()

y[::5] += 3 * (0.5 - np.random.rand(8))


svr_rbfmodel = SVR(kernel='rbf', C=1e3, gamma=0.1)

svr_linear = SVR(kernel='linear', C=1e3)

svr_polynom = SVR(kernel='poly', C=1e3, degree=2)

y_rbfmodel = svr_rbfmodel.fit(X, y).predict(X)

y_linear = svr_linear.fit(X, y).predict(X)

y_polynom = svr_polynom.fit(X, y).predict(X)


plt.figure(figsize=(11,11))

plt.scatter(X, y, c='k', label='data')

plt.hold('on')

plt.plot(X, y_rbfmodel, c='g', label='RBF model')

plt.plot(X, y_linear, c='r', label='Linear model')

plt.plot(X, y_polynom, c='b', label='Polynomial model')

plt.xlabel('data')

plt.ylabel('target')

plt.title('Support Vector Regression')

plt.legend()

plt.show()





k-Means Clustering (k-평균 군집분석)

k-평균 군집분석은 데이터셋의 어떤 k 개의 영역들의 중심을 최선으로 표현할 수 있는 데이터셋의 k 개의 지점들을 찾아낸다.

이 알고리즘은 수행 전 군집의 숫자(k)를 분석가가 미리 정해주어야 한다는 단점이 있다.

그러나 k-평균 군집분석은 군집분석에 매우 많이 사용되는 방법이고, 어떤 가정도 요구하지 않는 강점을 가지고 있다.


k-평균 군집분석의 알고리즘을 간단하게 정리하면 다음과 같다.

- n개의 점 (x, y) 집합과 k개의 센트로이드 집합이 주어진다. (초기에는 랜덤하게 배정됨)

- 각 점 (x, y)에 대해, 그 지점에서 가장 가까운 센트로이드를 찾아 해당 점을 소속시킨다.

- 각 군집에서 중앙값을 찾고 이 값을 다음 k개의 센트로이드 집합으로 설정한다.

- 센트로이드 집합의 값이 변하지 않을 때까지 계속 반복한다.


다음 예제는 scikit-learn 라이브러리를 사용해 k-평균 군집분석을 구현한 파이썬 코드이다.


import matplotlib.pyplot as plt


from sklearn.cluster import KMeans


import csv


x=[]

y=[]


with open('./cluster_input.csv', 'r') as csvf:

  reader = csv.reader(csvf, delimiter=',')

  for row in reader:

      x.append(float(row[0]))

      y.append(float(row[1]))


data=[]

for i in range(0,120):

  data.append([x[i],y[i]])


plt.figure(figsize=(10,10))


plt.xlim(0,12)

plt.ylim(0,12)


plt.xlabel("X values",fontsize=14)

plt.ylabel("Y values", fontsize=14)


plt.title("Before Clustering ", fontsize=20)


plt.plot(x, y, 'k.', color='#0080ff', markersize=35, alpha=0.6)


kmeans = KMeans(init='k-means++', n_clusters=3, n_init=10)

kmeans.fit(data)


plt.figure(figsize=(10,10))


plt.xlim(0,12)

plt.ylim(0,12)


plt.xlabel("X values",fontsize=14)

plt.ylabel("Y values", fontsize=14)


plt.title("After K-Means Clustering (from scikit-learn)", fontsize=20)


plt.plot(x, y, 'k.', color='#ffaaaa', markersize=45, alpha=0.6)


# Plot the centroids as a blue X

centroids = kmeans.cluster_centers_


plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', s=200,

  linewidths=3, color='b', zorder=10)


plt.show()






※ 이 포스팅은 저자 'Kirthi Raman'의 도서 <Mastering Python Data Visualization> 을 공부하며 정리한 글입니다. 



Chapter 05. Financial and Statistical Models (금융과 통계 모형)


( 이전 포스팅에 이어서 .. )

An Overview of Statistical and Machine Learning (통계 및 머신러닝 개요)

머신러닝은 인간이 수행하기에 충분히 간단한 분류식들을 생성하는 것을 목표로 한다.

머신러닝은 결정 프로세스에 대한 통찰력을 제공하기 위해 인간의 추론을 충분히 모방해야만 한다.

통계와 유사하게 배경 지식은 개발 단계에서 활용될 수 있다.


통계 학습과 머신 러닝의 차이는 추론 중심이냐 예측 중심이냐의 차이라고 볼 수 있다.



#. k-최근접 이웃 (k-Nearest Neighbor)

k-NN은 훈련 데이터로부터 모델을 구축하지 않는, 알고리즘이다. 

k-NN의 접근 방법은 다음과 같다.

- 어떤 방법이든 사용해 데이터를 수집

- 거리 계산에 필요한 수치 값을 준비

- 계산된 k-NN 이웃 검색에 대한 몇 가지 작업을 수행하고, 상위 k의 가까운 이웃을 식별


from numpy import random, argsort, sqrt

from pylab import plot, show

import matplotlib.pyplot as plt


def knn_search(x, data, K) :

    ndata = data.shape[1]

    K = K if K < ndata else ndata

    # 다른 지점으로부터의 유클리드 거리

    sqd = sqrt(((data - x[:,:ndata])**2).sum(axis=0))

    idx = argsort(sqd) # 정렬

    # k-NN 인덱스 반환

    return idx[:K]


data = random.rand(2,200)   # 랜덤 데이터 셋

x = random.rand(2,1)        # 쿼리 포인트


neig_idx = knn_search(x, data, 10)


plt.figure(figsize=(12, 12))


# 데이터와 입력 포인트를 플로팅한다.

plot(data[0,:], data[1,:], 'o', x[0, 0], x[1, 0], 'o', color='#9a88a1', markersize=20)

     

# 이웃들을 하이라이팅

plot(data[0, neig_idx], data[1, neig_idx], 'o', markerfacecolor='#bbe4b4', markersize=22, markeredgewidth=1)


show()




#. 일반화 선형 모델 (Generalized Linear Models)

회귀분석은 변수들 사이의 관계를 추정하는데 쓰이는 통계 프로세스다. 구체적으로, 회귀는 독립변수 중 하나가 변화할 때 종속 변수의 전형적인 값이 어떻게 변화하는지 이해하는 데 도움이 된다.


그 중 선형 회귀분석은 보간법(interpolation)을 적용할 수 있는 고전적인 방법이나 예측력은 부족하다. 또한, 이상치와 교차 상관관계에 민감하다.

선형 회귀모형은 목표 값(y)을 입력변수(x1, x2, ... xn)의 선형결합으로 다음과 같이 추정한다.

베이즈 회귀는 분리한 추정의 일종이며, 전통적인 선형 회귀보다 더 유연하고 안정적이다.

왜 베이즈를 사용하는가? 베이즈 모델은 더 유연하고, 작은 샘플에서 더 정확하며, 이전의 정보를 포함할 수 있기 때문이다.



#. 베이즈 선형 회귀 (Bayesian Linear Regression)

먼저, 선형 회귀를 위한 그래픽 모델을 살펴보자.

주어진 값을 다음과 같이 설정한다.



목표는 이 데이터를 모델링하여 다음과 같은 함수 식을 마련하는 것이다.

여기서 w는 가중치 벡터이고, 위의 식에 나타낸 것처럼 각 Yi는 정규분포를 따르게 된다.

Yi는 랜덤변수고, 데이터로부터 랜덤변수 Yi=yi의 각 조건의 변수 x값을 바탕으로 새로운 변수 x값을 대응하는 y를 예측할 수 있다.


import numpy as np

import matplotlib.pyplot as plt

from scipy import stats


from sklearn.linear_model import BayesianRidge


np.random.seed(0)

n_samples, n_features = 200, 200


X = np.random.randn(n_samples, n_features) # 가우시안 데이터

# 정밀도 4로 가중치를 만듦

theta = 4.

w = np.zeros(n_features)


# 관심 있는 8개의 가중치만 유지

relevant_features = np.random.randint(0, n_features, 8)

for i in relevant_features :

    w[i] = stats.norm.rvs(loc=0, scale=1. / np.sqrt(theta))

    

alpha_ = 50.

noise = stats.norm.rvs(loc=0, scale=1. / np.sqrt(alpha_), size=n_samples)

y = np.dot(X, w) + noise


# 베이즈 능형 회귀 (Bayesian Ridge Regression) 에 맞춤

clf = BayesianRidge(compute_score=True)

clf.fit(X, y)


# 가중치, 예측 및 히스토그램 가중치를 시각화

plt.figure(figsize=(11, 10))

plt.title("Weights of the model", fontsize=18)

plt.plot(clf.coef_, 'b-', label="Bayesian Ridge estimate")

plt.plot(w, 'g-', label="Training Set Accuracy")

plt.xlabel("Features", fontsize=16)

plt.ylabel("Values of the weights", fontsize=16)

plt.legend(loc="best", prop=dict(size=12))


plt.figure(figsize=(11, 10))

plt.title("Histogram of the weights", fontsize=18)

plt.hist(clf.coef_, bins=n_features, log=True)

plt.plot(clf.coef_[relevant_features], 5 * np.ones(len(relevant_features)),

         'ro', label="Relevant features")

plt.ylabel("features", fontsize=16)

plt.xlabel("Values of the weights", fontsize=16)

plt.legend(loc="lower left")

plt.show()





#. 애니메이션 및 인터랙티브 플롯 작성

Bokeh, Plotly, VisPy 등의 인터랙티브한 그래프 작성 도구들이 있다.


Bokeh는 인터랙션하는 부분을 쉽게 하기 위해 자바스크립트와 D3.js로 matplotlib 객체를 시각화할 수 있으며, 큰 데이터셋에서도 좋은 성능을 제공한다.


#import bokeh

#bokeh.sampledata.download() # 이 2개 라인은 최초만 실행하면 됨


from bokeh.sampledata import us_counties, unemployment

from bokeh.plotting import figure, show, output_file

from bokeh.models import HoverTool


import collections

from collections import OrderedDict


county_coordinate_xs=[

        us_counties.data[code]['lons'] for code in us_counties.data

        if us_counties.data[code]['state'] == 'ca'

        ]

county_coordinate_ys=[

        us_counties.data[code]['lats'] for code in us_counties.data

        if us_counties.data[code]['state'] == 'ca'

        ]


colors = ["#e6f2ff", "#cce5ff", "#99cbff", "#b2d8ff", "#73abe5", "#5985b2"]

county_colors = []

for county_id in us_counties.data :

    if us_counties.data[county_id]['state'] != 'ca' :

        continue

    try :

        rate = unemployment.data[county_id]

        idx = min(int(rate/2), 5)

        county_colors.append(colors[idx])

    except KeyError :

        county_colors.append("black")


output_file("california.html", title="california.py example")


TOOLS="pan, wheel_zoom, box_zoom, reset, hover, save"

p = figure(title="California Unemployment 2009",

           width=1000, height=1000, tools=TOOLS)


p.patches(county_coordinate_xs, county_coordinate_ys,

          fill_color=county_colors, fill_alpha=0.7,

          line_color="white", line_width=0.5)


mouse_hover = p.select(dict(type=HoverTool))

mouse_hover.point_policy = "follow_mouse"

mouse_hover.tooltips = collections.OrderedDict([

        ("index", "$index"), ("(x, y)", "($x, $y)"),

        ("fill color", "$color[hex, swatch]:fill_color"),])


show(p)



Plotly는 인터랙티브한 그래프 시각화를 제공하는 또 다른 옵션이다.

그러나 참고로, 온라인상에 있어야 하고 Plotly 계정이 필요하다.


VisPy는 파이썬과 OpenGL을 사용해 만들어진 고성능 인터랙티브 도구로, 최신 GPU 성능을 제공하는 라이브러리이다.




+ Recent posts