블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

t-SNE를 이용한 차원 감소


조대협 (http://bcho.tistory.com)


PCA 기반 차원 감소의 문제점

앞의 글에서 차원 감소에 대한 개념과, 차원 감소 알고리즘의 하나인 PCA 알고리즘에 대해서 살펴보았다.

PCA의 경우 선형 분석 방식으로 값을 사상하기 때문에 차원이 감소되면서 군집화 되어 있는 데이타들이 뭉게져서 제대로 구별할 수 없는 문제를 가지고 있다. 아래 그림을 보자


출처 https://www.youtube.com/watch?v=NEaUSP4YerM


이 그림은 2차원에서 1차원으로 PCA 분석을 이용하여 차원을 줄인 예인데, 2차원에서는 파란색과 붉은색이 구별이 되는데, 1차원으로 줄면서 1차원상의 위치가 유사한 바람에, 두 군집의 변별력이 없어져 버렸다.

t-SNE

이런 문제를 해결하기 위한 차원 감소 방법으로는 t-SNE (티스니라고 읽음) 방식이 있는데, 대략적인 원리는 다음과 같다.


먼저 점을 하나 선택한다. 아래는 검정색점을 선택했는데, 이 점에서 부터 다른점까지의 거리를 측정한다.



다음 T 분포 그래프를 이용하여, 검정 점(기준점) 을 T 분포 상의 가운데 위치한다면, 기준점으로부터 상대점 까지 거리에 있는 T 분포의 값을 선택(위의 T 분포 그래프에서 파란점에서 위로 점섬이 올라가서 T분포 그래프상에 붉은 색으로 X 표가 되어 있는 값)하여, 이 값을 친밀도 (Similarity)로 하고, 이 친밀도가 가까운 값끼리 묶는다.


이 경우 PCA 처럼 군집이 중복되지 않는 장점은 있지만, 매번 계산할때 마다 축의 위치가 바뀌어서, 다른 모양으로 나타난다. 단 데이타의 군집성과 같은 특성들은 유지 되기 때문에 시각화를 통한 데이타 분석에는 유용하지만, 매번 값이 바뀌는 특성으로 인하여, 머신러닝 모델의 학습 피쳐로 사용하기는 다소 어려운점이 있다.


아래 그림은 같은 데이타로 t-SNE 분석을 각각 한번씩한 결과를 시각화 해서 표현한 결과 인데, 보는 것과 같이 군집에 대한 특성은 그대로 유지 되지만 값 자체는 변화가 된것을 확인할 수 있다.




sklearn 을 이용한 t-SNE 구현

전체 코드는 https://github.com/bwcho75/dataanalyticsandML/blob/master/dimension%20reduction/2.%20t-SNE%20visualization.ipynb 에 공개되어 있으니 참고하기 바란다.


# Perform the necessary imports
import matplotlib.pyplot as plt
from sklearn.manifold import TSNE

model = TSNE(learning_rate=100)
transformed = model.fit_transform(feature)

xs = transformed[:,0]
ys = transformed[:,1]
plt.scatter(xs,ys,c=labels)

plt.show()


사실 코드가 너무 간단해서 설명할것이 없다. TSNE 객체를 선언하고 학습속도 (learning_rate)를 지정한다음 fit_transform 하면 끝이다. (싸이킷런 만세…)


다음글에서는 차원 감소 방법중에 마지막을 Matrix Factorization (행렬 인수 분해) 방법에 대해서 알아보도록 하겠다.






DBSCAN (밀도 기반 클러스터링)


조대협(http://bcho.tistory.com)

기본 개념

이번에는 클러스터링 알고리즘중 밀도 방식의 클러스터링을 사용하는 DBSCAN(Density-based spatial clustering of applications with noise) 에 대해서 알아보도록 한다.

앞에서 설명한 K Means나 Hierarchical 클러스터링의 경우 군집간의 거리를 이용하여 클러스터링을 하는 방법인데, 밀도 기반의 클러스터링은 점이 세밀하게 몰려 있어서 밀도가 높은 부분을 클러스터링 하는 방식이다.

쉽게 설명하면, 어느점을 기준으로 반경 x내에 점이 n개 이상 있으면 하나의 군집으로 인식하는 방식이다.


그러면 조금 더 구체적인 개념과 용어를 이해해보자

먼저 점 p가 있다고 할때, 점 p에서 부터 거리 e (epsilon)내에 점이 m(minPts) 개 있으면 하나의 군집으로 인식한다고 하자. 이 조건 즉 거리 e 내에 점 m개를 가지고 있는 점 p를 core point (중심점) 이라고 한다.

DBSCAN 알고리즘을 사용하려면 기준점 부터의 거리 epsilon값과, 이 반경내에 있는 점의 수 minPts를 인자로 전달해야 한다.


아래 그림에서 minPts = 4 라고 하면, 파란점 P를 중심으로 반경 epsilon 내에 점이 4개 이상 있으면 하나의 군집으로 판단할 수 있는데, 아래 그림은 점이 5개가 있기 때문에 하나의 군집으로 판단이 되고, P는 core point가 된다.



아래 그림에서 회색점 P2의 경우 점 P2를 기반으로 epsilon 반경내의 점이 3개 이기 때문에, minPts=4에 미치지 못하기 때문에, 군집의 중심이 되는 core point는 되지 못하지만, 앞의 점 P를 core point로 하는 군집에는 속하기 때문에 이를 boder point (경계점)이라고 한다.



아래 그림에서 P3는 epsilon 반경내에 점 4개를 가지고 있기 때문에 core point가 된다.



그런데 P3를 중심으로 하는 반경내에 다른 core point P가 포함이 되어 있는데, 이 경우 core point P와  P3는 연결되어 있다고 하고 하나의 군집으로 묶이게 된다.


마지막으로 아래 그림의 P4는 어떤 점을 중심으로 하더라도 minPts=4를 만족하는 범위에 포함이 되지 않는다. 즉 어느 군집에도 속하지 않는 outlier가 되는데, 이를 noise point라고 한다.


이를 모두 정리해보면 다음과 같은 그림이 나온다.


정리해서 이야기 하면, 점을 중심으로 epsilon 반경내에 minPts 이상수의 점이 있으면 그 점을 중심으로 군집이 되고 그 점을 core point라고 한다. Core point 가 서로 다른 core point의 군집의 일부가 되면 그 군집을 서로 연결되어 있다고 하고 하나의 군집으로 연결을 한다.

군집에는 속하지만, 스스로 core point가 안되는 점을 border point라고 하고, 주로 클러스터의 외곽을 이루는 점이 된다.

그리고 어느 클러스터에도 속하지 않는 점은 Noise point가 된다.

장점

DBSCAN 알고리즘의 장점은

  • K Means와 같이 클러스터의 수를 정하지 않아도 되며,

  • 클러스터의 밀도에 따라서 클러스터를 서로 연결하기 때문에 기하학적인 모양을 갖는 군집도 잘 찾을 수 있으며


    기하학적인 구조를 군집화한 예 (출처 : https://en.wikipedia.org/wiki/DBSCAN )

  • Noise point를 통하여, outlier 검출이 가능하다.

예제 코드

코드의 내용은 앞과 거의 유사하다.


model = DBSCAN(eps=0.3,min_samples=6)


모델 부분만 DBSCAN으로 바꿔 주고, epsilon 값은 eps에 minPts값은 min_samples 인자로 넘겨주면 된다. 이 예제에서는 각각 0.3 과 6을 주었다.


전체 코드를 보면 다음과 같다.


import pandas as pd
iris = datasets.load_iris()

labels = pd.DataFrame(iris.target)
labels.columns=['labels']
data = pd.DataFrame(iris.data)
data.columns=['Sepal length','Sepal width','Petal length','Petal width']
data = pd.concat([data,labels],axis=1)

data.head()



IRIS 데이타를 DataFrame으로 로딩 한 다음, 학습에 사용할 피쳐를 다음과 같이 feature 변수에 저장한다.


feature = data[ ['Sepal length','Sepal width','Petal length','Petal width']]
feature.head()


다음은 모델을 선언하고, 데이타를 넣어서 학습을 시킨다.


from sklearn.cluster import DBSCAN
import matplotlib.pyplot  as plt
import seaborn as sns

# create model and prediction
model = DBSCAN(min_samples=6)
predict = pd.DataFrame(model.fit_predict(feature))
predict.columns=['predict']

# concatenate labels to df as a new column
r = pd.concat([feature,predict],axis=1)


다음은 모델을 선언하고, 데이타를 넣어서 학습을 시킨다.

학습이 끝난 결과를 다음과 같이 3차원 그래프로 시각화 해보자. 아래 시각화는 3차원인데, 학습은 4차원으로 하였다. 그래서 다소 오류가 있어 보일 수 있다. 다차원 데이타를 시각화 하기위해서는 PCA나 t-SNE와 같은 차원 감소 (dimensional reduction) 기법을 사용해야 하는데,  이는 다음 글에서 다루도록한다.


from mpl_toolkits.mplot3d import Axes3D
# scatter plot
fig = plt.figure( figsize=(6,6))
ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134)
ax.scatter(r['Sepal length'],r['Sepal width'],r['Petal length'],c=r['predict'],alpha=0.5)
ax.set_xlabel('Sepal lenth')
ax.set_ylabel('Sepal width')
ax.set_zlabel('Petal length')
plt.show()







마지막으로 Cross tabulazation 을 이용하여 모델을 검증해보면 다음과 같은 결과를 얻을 수 있다.

ct = pd.crosstab(data['labels'],r['predict'])
print (ct)



이 코드에 대한 전체 내용은 https://github.com/bwcho75/dataanalyticsandML/blob/master/Clustering/5.%20DBSCANClustering-IRIS%204%20feature-Copy1.ipynb 에서 확인할 수 있다.

Hierarchical clustering을 이용한 데이타 군집화


조대협 (http://bcho.tistory.com)


Hierarchical clustering (한글 : 계층적 군집 분석) 은 비슷한 군집끼리 묶어 가면서 최종 적으로는 하나의 케이스가 될때까지 군집을 묶는 클러스터링 알고리즘이다.

군집간의 거리를 기반으로 클러스터링을 하는 알고리즘이며, K Means와는 다르게 군집의 수를 미리 정해주지 않아도 된다. 참고로 이 글에서 사용된 예제 코드는 https://github.com/bwcho75/dataanalyticsandML/blob/master/Clustering/3.%20Hierarchical%20clustering-IRIS%204%20feature.ipynb 에 저장되어 있다.


예를 들어서 설명해보자

“진돗개,세퍼드,요크셔테리어,푸들, 물소, 젖소" 를 계층적 군집 분석을 하게 되면

첫번째는 중형견, 소형견, 소와 같은 군집으로 3개의 군집으로 묶일 수 있다.


이를 한번 더 군집화 하게 되면 [진돗개,셰퍼드] 와 [요크셔테리어,푸들] 군집은 하나의 군집(개)로 묶일 수 있다.


마지막으로 한번 더 군집화를 하게 되면 전체가 한군집(동물)으로 묶이게 된다.


이렇게 단계별로 계층을 따라가면서 군집을 하는 것을 계층적 군집 분석이라고 한다.

계층적 군집 분석은 Dendrogram이라는 그래프를 이용하면 손쉽게 시각화 할 수 있다.





계층형 군집화에 대한 좀 더 상세한 개념은 https://www.slideshare.net/pierluca.lanzi/dmtm-lecture-12-hierarchical-clustering?qid=94d8b25a-8cfa-421c-9ed5-03c0b33c29fb&v=&b=&from_search=1 를 보면 잘 나와 있다.


skLearn을 이용한 계층 분석 모델 구현

개념을 잡았으면 실제로 계층 분석 모델을 구현해보자.

데이타는 K Means에서 사용했던 IRIS 데이타를 똑같이 사용한다.

이번에는 4개의 피쳐를 이용해서 사용한다.


from sklearn import datasets
import pandas as pd
iris = datasets.load_iris()

labels = pd.DataFrame(iris.target)
labels.columns=['labels']
data = pd.DataFrame(iris.data)
data.columns=['Sepal length','Sepal width','Petal length','Petal width']
data = pd.concat([data,labels],axis=1)


다음은 IRIS 데이타를 이용하여 dendrogram을 그려보자

# Perform the necessary imports
from scipy.cluster.hierarchy import linkage, dendrogram
import matplotlib.pyplot as plt

# Calculate the linkage: mergings
mergings = linkage(data,method='complete')

# Plot the dendrogram, using varieties as labels
plt.figure(figsize=(40,20))
dendrogram(mergings,
          labels = labels.as_matrix(columns=['labels']),
          leaf_rotation=90,
          leaf_font_size=20,
)
plt.show()


먼저 linkage 함수를 import 한 다음 linkage 함수에 data를 넘겨주면 Hierarchical clustering을 수행한다. 이때 method=’complete’로 정했는데, 이 부분은 뒤에서 설명한다.

Hierarchical clustering 한 결과를 dendrogram 함수를 이용하여 dendrogram 그래프를 표현해 보면 다음과 같이 출력된다.




계층 분석 방식

앞의 코드에서, linkage 함수에서 method 를 사용했다. 이에 대해서 알아보자.

Hierachical clustering의 기본 원리는 두 클러스터 사이의 거리를 측정해서 거리가 가까운 클러스터끼리 묶는 방식이다.  그러면 두 클러스터의 거리를 측정할때 어디를 기준점으로 할것인가를 결정해야 하는데 다음 그림을 보자.



출처 : https://www.multid.se/genex/onlinehelp/hs515.htm


앞의 코드에서 사용한 complete linkage 방식은 두 클러스터상에서 가장 먼 거리를 이용해서 측정하는 방식이고 반대로  single linkage 방식은 두 클러스터에서 가장 가까운 거리를 사용하는 방식이다.

average linkage 방식은 각 클러스터내의 각 점에서 다른 클러스터내의 모든 점사이의 거리에 대한 평균을 사용하는 방식이다.


이 linkage 방식에 따라서 군집이 되는 모양이 다르기 때문에, 데이타의 분포에 따라서 적절한 linkage  방식을 변화 시켜가면서 적용해가는 것이 좋다.


계층 분석을 통한 군집의 결정

계층 분석은 최종적으로 1개의 군집으로 모든 데이타를 클러스터링 하는데, 그렇다면 n개의 군집으로 나누려면 어떻게 해야 하는가?

아래 dendrogram을 보자 y축이 각 클러스터간의 거리를 나타내는데, 위로 올라갈 수 록 클러스터가 병합되는 것을 볼 수 있다.




즉 적정 y 값에서 클러스터링을 멈추면 n개의 군집 까지만 클러스터링이 되는데, 위의 그림은 y 값을 3에서 클러스터링을 멈춰서 총 3개의 클러스터로 구분을 한 결과이다.


이렇게 계층형 분석에서 sklearn을 사용할 경우 fcluster 함수를 이용하면, 특정 y값에서 클러스터링을 멈출 수 있다. 다음 코드를 보자.


from scipy.cluster.hierarchy import fcluster

predict = pd.DataFrame(fcluster(mergings,3,criterion='distance'))
predict.columns=['predict']
ct = pd.crosstab(predict['predict'],labels['labels'])
print(ct)


앞의 코드에서 계층형 클러스터링을 한 mergings 변수를 fcluster 함수에 전달하고 두번째 인자에 y의 임계값을 3으로 지정하였다. Predict 컬럼에는 원본 입력데이타에 대한 예측 결과 (어느 클러스터에 속해있는지를 0,1,2로 입력 데이타의 수만큼 리턴한다.)를 리턴한다.


이를 원본 데이타의 라벨인 labels[‘label’]값과 Cross tabulation 분석을 해보았다.




세로축이 예측 결과, 가로측이 원래 값이다.

원래 label이 0인 데이타와 1인 데이타는 각각 잘 분류가 되었고, 2인 데이타는 34개만 정확하게 분류가 되었고 16개는 원본 레이블이 1인 데이타로 분류가 되었다.


지금까지 Hierachical clustering model에 대해서 알아보았다. K Means와 같은 군집화 모델이라도 내부 알고리즘에 따라서 군집화 결과가 다르기 때문에, 샘플 데이타의 분포를 보고 적절한 클러스터링 모델을 고르는 것이 필요하다. 다행이 sklearn의 경우 복잡한 수식 이해 없이도 간단한 라이브러리 형태로 다양한 클러스터링 모델 사용할 수 있도록 해놨기 때문에, 여러 모델을 적용해가면서 적정한 데이타 분류 방식을 찾아보는 것이 어떨까 한다.




파이썬을 이용한 데이타 시각화 #1 - Matplotlib 기본 그래프 그리기


조대협 (http://bcho.tistory.com)


백앤드 엔지니어와 백그라운드를 가진 경험상, 머신러닝을 공부하면서 헷갈렸던 부분중 하나가, 데이타에 대한 시각화이다. 머신러닝은 모델을 구현하는 것도 중요하지만, 학습할 데이타를 선별하고, 만들어진 모델을 검증하기 위해서는 데이타를 이해하는 것이 필수적이고 이를 위해서는 데이타를 시각화 해서 보는 것이 매우 중요하다.


그동안 그래프를 그리는 것을 스택오버플로우등에서 찾아서 복붙을 해서 사용하다가 matplotlib를 정리해야겠다고 해서 메뉴얼을 봤지만 도무지 이해가 되지 않아서, 결국 온라인 강좌를 들어서 정리해봤는데, 역시 강좌를 들으니까는 훨씬 빠르게 이해가 된다.

참고한 코스는 datacamp에 있는 “Introduction to Data Visualization with Python” 코스이다.


오늘은 matplotlib를 이용하여 기본적인 그래프를 그리는 방법에 대해서 정리하도록 한다.

기본 그래프 그리기

기본적인 그래프를 그리기 위해서는 matplotlib.pyplot에서  plot(x,y)를 사용하면 된다. x,y는 각각 X축과 Y축의 값이 된다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x*5

plt.plot(x,y)
plt.show()


색깔 바꾸기

그래프를 그릴때 선의 색을 지정하기 위해서는 plot에서 인자로 컬러를 주면된다. 컬러표는 아래를 참고하면 되고 붉은색은 r, 파란색은 b으로 정의한다.

from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x*5

plt.plot(x,y,'r')
plt.show()





선 종류 변경하기

선을 그릴때, 다양한 선의 종류를 선택할 수 있다. 디폴트가 직선이고, 점으로 표현하는 마커나 점선등을 선택할 수 있다.

선의 선택은 plot에서 세번째 인자에 선의 종류를 지정하면 되고, 색을 같이 지정하려면 다음문자에 색을 지정하면 된다 다음은 동그란 마커 ‘o’를 붉은색 ‘r’로 표현하기 때문에, 세번째 인자를 ‘or’로 전달하였다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x*5

plt.plot(x,y,'or')
plt.show()




다음은 선에 대한 종류표이다.



라벨과 타이틀

그래프를 그릴때 그래프의 타이틀과 X,Y축의 라벨을 표현하기 위해서는 타이틀은 plt.title(“타이틀명"),  X,Y축에 대한 라벨은 plt.xlabel(‘X축 라벨명'), plt.ylabel(‘Y축 라벨명') 을 사용한다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x*5

plt.plot(x,y)
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.title('matplotlib sample')
plt.show()



구간 확대/축소

그래프는 입력되는 x,y의 최소,최대 구간으로 자동으로 그려지는데, 이 구간을 키우거나 줄이기 위해서 x,y의 구간을 정의할 수 있다. x축은 plt.xlim(최소,최대),  y축은 plt.ylim(최소,최대)로 정의하면 된다.

아래는 x축을 2~3, y축을 5~20으로 확대해서 그래프를 그리는 예제이다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x*5

plt.xlim(2,3)
plt.ylim(5,20)
plt.plot(x,y)
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.title('matplotlib sample')
plt.show()



레전드

그래프를 그릴때 여러개의 그래프를 같이 그릴 수 있는데, 이경우 각 그래프가 구분이 안되기 때문에, 그래프마다 라벨을 달고 이 라벨명을 출력할 수 있는데, 이를 legend라고 한다.

아래는 first와 second 라는 두개의 그래프를 그리고, 우측 상단에 legend를 표현한 예이다.

legend를 사용하기 위해서는 plt.plot에서 label 변수에 그래프의 이름을 정의하고, plt.legend(‘위치')를 정해주면  legend를 그래프상에 표현해주는데, legend의 위치는 아래 표를 참고하면 된다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10,0.1)
y = x*0.2
y2 = np.sin(x)

plt.plot(x,y,'b',label='first')
plt.plot(x,y2,'r',label='second')
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.title('matplotlib sample')
plt.legend(loc='upper right')
plt.show()



어노테이션

다음은 어노테이션이라는 기능으로, 그래프에 화살표를 그린후, 그 화살표에 문자열을 출력하는 기능이다. 예를들어 “이값이 최소값" 이런식으로 화살표를 그려서 표현할때 사용하는데 plt.annotate 함수를 사용하면 된다.

plt.annotate(‘문자열',xy,xytext,arrowprops) 식으로 사용한다.

문자열은 어노테이션에서 나타낼 문자열이고, xy는 화살표가 가르키는 점의 위치, xytext는 문자열이 출력될 위치, arrowprops는 화살표의 속성으로 칼라등을 정의한다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x*5

plt.plot(x,y)
plt.annotate('annotate',xy=(2,10),xytext=(5,20),arrowprops={'color':'green'})
plt.show()



서브플롯

여러개의 그래프를 그리고 싶을때가 있는데, 이 경우 서브플롯이라는 것을 사용한다. 서브플롯은 그래프가 그려질 위치를 격자형으로 지정하는데, plt.subplot(nrow,ncol,pos) 식으로 사용한다.

nrow,ncol은 그래프를 그린 plain의 크기를 지정하는데, 3,2면 3줄로, 가로는 2칸으로 된 그래프 plain 설정한다. 그리고 마자막 pos는 몇번째 plain에 그래프를 그릴지 지정하는데, 아래와 같이 상단에서 부터 우측,아래 방향으로 1,2,3,4,5,6 순서가 된다.


1

2

3

4

5

6



아래 그림은 2,1 크기의 plain 을 만들어놓고 그래프를 위,아래로 두개를 그리는 예제이다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y1 = x*5
y2 = x*1
y3 = x*0.3
y4 = x*0.2

plt.subplot(2,1,1)
plt.plot(x,y1)
plt.subplot(2,1,2)
plt.plot(x,y2)
plt.show()



아래 그림은 한줄의 두칸 plain을 만들어놓고, 좌우에 두개의 그래프를 그린 예제이다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y1 = x*5
y2 = x*1
y3 = x*0.3
y4 = x*0.2

plt.subplot(1,2,1)
plt.plot(x,y1)
plt.subplot(1,2,2)
plt.plot(x,y2)
plt.show()




다음은 2x2 plain으로 4개의 그래프를 그린 예제이다.


from matplotlib import pyplot as plt
import numpy as np

x = np.arange(1,10)
y1 = x*5
y2 = x*1
y3 = x*0.3
y4 = x*0.2

plt.subplot(2,2,1)
plt.plot(x,y1)
plt.subplot(2,2,2)
plt.plot(x,y2)
plt.subplot(2,2,3)
plt.plot(x,y3)
plt.subplot(2,2,4)
plt.plot(x,y4)
plt.show()


그래프 사이즈

그래프를 크게 그리고 싶을때 그래프 자체의 크기를 변경할 수 있는데, plt.figure를 이용하여 figsize=(가로,세로)를 인자로 주면 그래프가 그려질 전체 그림의 크기를 조절할 수 있다. 아래는 20x5 크기로 그래프를 그릴 크기를 지정하는 예제이다.


import numpy as np

x = np.arange(1,10)
y1 = x*5
y2 = x*1
y3 = x*0.3
y4 = x*0.2

plt.figure(figsize=(20,5))
plt.subplot(2,2,1)
plt.plot(x,y1)
plt.subplot(2,2,2)
plt.plot(x,y2)
plt.subplot(2,2,3)
plt.plot(x,y3)
plt.subplot(2,2,4)
plt.plot(x,y4)
plt.show()




지금까지 간단하게 matplotlib를 이용하여 기본 그래프를 그리는 방법에 대해서 알아보았다. 다음글은 바차트,히스토그램등 다양한 그래프 타입에 대해서 알아본다.


파이썬 전역 변수

프로그래밍/Python | 2017.04.11 00:05 | Posted by 조대협

파이썬에서 전역변수 사용하기 (2.7X 버전)


조대협 (http://bcho.tistory.com)


파이썬에서 전역 변수를 사용하려고 하니 "Unbound Local Error"가 나더라.

파이썬은 로컬 변수를 자바처럼 쓸수가 없다.


잘못된 코드


global_value = 1


def myfunction():

  global_value=global_value + 1


올바른 코드


global_value = 1


def myfunction():

  global global_value

  global_value=global_value + 1


글로벌 변수로 쓰려면, 글로벌 변수를 쓰려는 곳에서 global 이라는 키워드로 선언을 해줘야 그 전역 변수를 불러다가 쓸 수 있다.



Fluentd + Bigquery + Jupyter를 이용한 초간단 BI 구축하기


조대협

얼마전에 빅데이타의 전문가로 유명한 김형준님이 "Presto + Zeppelin을 이용한 초간단 BI 구축 사례"라는 발표 자료를 보았다. http://www.slideshare.net/babokim/presto-zeppelin-bi 오픈 소스 기술들을 조합하여, 초간단하게 빅데이타 분석 플랫폼을 만든 사례 인데, 상당히 실용적이기도 하고, 좋은 조합인것 같아서, 마침 구글 빅쿼리에 대한 자료를 정리하던중 비슷한 시나리오로 BI 대쉬 보드를 만들어보았다.

Fluentd를 이용해서 실시간으로 데이타를 수집하고, 이를 빅쿼리에 저장한 다음에 iPython nodebook (aka Jupyter)로 대쉬보드를 만드는 예제이다. 일부 제품에 대한 지식이 없었음에도 불구하고 실제 설정은 대략 2시간 정도 걸렸다.


아래 이제 예제는 정상적으로 작동 하지 않습니다. 트위터에서 JSON 스키마를 변경했는데, 거기에 맞는 빅쿼리 JSON 스키마를 구하기가 어렵네요. (만들자니 귀찮고). 참고로만 사용하세요



Fluentd 설치

예제는 Google Cloud에서 Ubuntu Linux 14.x VM에서 Fluentd를 이용하여 Twitter에서 데이타를 읽은 후, 빅쿼리에 데이타를 로딩하는 시나리오이다.

VM 생성

Fluentd를 설치할 VM을 생성해보자. 구글 클라우드 콘솔에서 아래 그림과 같이 VM을 생성할때, “Identity and API access” 부분에  “Allow full access to all Cloud APIs”를 선택한다. 이를 선택해서 이 VM이 모든 구글 클라우드 API에 대한 접근 권한 (BigQuery 포함)을 가지도록 한다.


tdagent 설치

생성한 VM에 fluentd의 로그 수집 에이전트인 tdagent를 설치한다.

tdagent는 OS나, 또는 같은 OS라도 OS 버전별로 설치 방법이 다르기 때문에, 버전별 설치 방법은 http://www.fluentd.org를 참고하기 바란다.

여기서는 Ubuntu 14.x를 기준으로 진행을 하였다.

다음 명령어를 실행하면 tdagent가 설치된다.

% curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh

설치한 후 에이전트를 실행해서 확인해보자. 다음 명령으로 agent를 실행한 후에,

% sudo /etc/init.d/td-agent restart

실행이 끝난 후에 다음 명령으로 설치를 확인한다.

% sudo /etc/init.d/td-agent status


참고 (tdagent 관련 명령어)

tdagent 기동 - $sudo /etc/init.d/td-agent start
tdagent 정지 - $sudo /etc/init.d/td-agent stop
tdagent 재시작 - $sudo /etc/init.d/td-agent restart
tdagent 상태확인 - $sudo /etc/init.d/td-agent status




트위터 Input 설정하기

tdagent 에이전트 설치가 끝났으면 fluentd를 이용해서 트위터 피드를 읽어드리도록 해보자.

트위터 API 키 받기

트위터 피드는 트위터에서 제공하는 OPEN API를 통해서 읽어드린다. 그래서 이 OPEN API에 접근하기 위해서는 OPEN API키가 필요하다.

OPEN API 키는 https://apps.twitter.com/ 에 접속하고 Create New App 메뉴를 이용하면 새로운 앱을 등록할 수 있고, 여기에 Fluentd 앱을 정의해서 정보를 넣어주고 Key and secrect을 생성해주면 다음과 같이 키가 생성된 것을 웹에서 확인할 수 있다.


여기서 필요한 키값은 Consumer Key, Consumer Secret, Access Token, Access Token Secret 4가지가 필요하다.

트위터 플러그인 설치하기

API 접근을 위한 API Key를 모두 얻었으면 이제 fluentd에서 트위터 피드를 읽기 위한 트위터 플러그인을 설치해보자.

트위터 API는 libssl에 대한 의존성이 있기 때문에, libssl를 먼저 설치한다.

%sudo apt-get install build-essential libssl-dev

다음 트위터 플러그인이 사용하는 eventmachine 플러그인과, 트위터 플러그인을 설치한다.

% sudo td-agent-gem install eventmachine

% sudo td-agent-gem install fluent-plugin-twitter

설정하기

플러그인 설치가 끝났으면 설정을 해보자. 설정 파일은 /etc/td-agent/td-agent.conf 에 있다.

이 파일을 다음과 같이 편집하자.


<source>

 type twitter

 consumer_key        {앞서 트위터 콘솔에서 받은 Consumer Key}

 consumer_secret     {앞서 트위터 콘솔에서 받은 Consumer  secret}

 oauth_token         {앞서 트위터 콘솔에서 받은 Access token}

 oauth_token_secret {앞서 트위터 콘솔에서 받은 Access token secret}

 tag                 input.twitter.sampling  # Required

 timeline            sampling                # Required (tracking or sampling or location or userstream)

 keyword             galaxy,game        # 검색어

 output_format       nest                   # Optional (nest or flat or simple[default])

</source>

<match input.twitter.sampling>

 type stdout

</match>


이 설정 파일은 keyword에 등록된 “galaxy”와 “game” 이라는 키워드를 찾아서, 읽어드린후 <match input.twitter.sampling> 에 의해서, 읽어드린 내용을 stdout으로 출력해주는 설정이다.

테스트

설정이 끝났으면 확인을 해보자

% sudo /etc/init.d/td-agent restart

명령어를 수행하여, td-agent를 리스타트 해서 새로운 config 파일이 반영되도록 하고

% tail -f /var/log/td-agent/td-agent.log          

를 통해서 stdout으로 올라오는 로그를 확인하자. 제대로 데이타가 수집되는 것을 확인했으면 다음 명령어를 이용해서, td-agent를 정지 시키자.

% sudo /etc/init.d/td-agent stop


빅쿼리로 저장하기

twitter로 부터 피드를 읽어드리는 플러그인이 정상적으로 작동함을 확인하였으면, 이번에는 읽어드린 데이타를 빅쿼리로 저장해보자.

빅쿼리 플러그인 설치 및 테이블 생성

빅쿼리로 데이타를 쓰기 위해서 빅쿼리 플러그인을 설치한다.

% sudo td-agent-gem install fluent-plugin-bigquery


다음으로 빅쿼리 프로젝트에서 트위터 데이타를 저장할 데이타셋과 테이블을 생성한다.

데이타 셋 이름은 편의상 “twitter”라고 하고, 테이블은 “ timeline”이라고 하고 생성을 하겠다.

테이블의 스키마는 트위터 피드에 대한 데이타 구조를 빅쿼리 스키마로 만들어놓은 스키마가 이미 https://gist.github.com/Salinger/ef39b81ad2c48516b596

에 있기 때문에, 이 스키마 파일을 읽어서 빅쿼리 콘솔에서 아래 그림과 같이 Schema 부분에 Copy & Paste를 해서 붙이면 테이블이 생성된다.


설정하기

테이블이 생성이 되었으면 fluentd 설정 파일을 수정하여 트위터 피드를 이 테이블에 저장하도록 설정한다.


<source>
 type twitter
   consumer_key        {앞서 트위터 콘솔에서 받은 Consumer Key}

 consumer_secret     {앞서 트위터 콘솔에서 받은 Consumer  secret}

 oauth_token         {앞서 트위터 콘솔에서 받은 Access token}

 oauth_token_secret {앞서 트위터 콘솔에서 받은 Access token secret}

 tag                 input.twitter.sampling  # Required
 timeline            sampling                # Required (tracking or sampling or location or userstream)
 keyword             hillary,clinton,donald,trump
 output_format       nest                    # Optional (nest or flat or simple[default])
</source>

<match input.twitter.sampling>
 type copy
<store>
  type bigquery
  buffer_type file
  buffer_path /var/log/td-agent/buffer/twi.*.buf
  method insert

  auth_method compute_engine
  project useful-hour-138023
  dataset twitter
  table timeline

  flush_interval 1
  buffer_chunk_limit 1000000
  buffer_queue_limit 5000
  flush_interval 1
  try_flush_interval 0.05
  num_threads 4
  queue_chunk_flush_interval 0.01

  time_format %s
  time_field log_time
  schema_path /home/terrycho/bq_tweet.json
  log_level error
</store>
</match>


기존 설정 파일에서 <match input.twitter.sampling> 부분을 빅쿼리로 변경하였다. <store>에서 type을 bigquery로 변경하였다.

중요한 필드들을 살펴보면

  • buffer_type, buffer_path : fluentd는 트위터에서 읽어드리는 데이타를 건건이 bigquery에 저장하는게 아니라 일정 단위로 모아서 bigquery에 저장한다. 그래서 buffer를 사용하는데, buffer를 파일을 이용하고, 이 파일의 위치를 지정해주었다.

  • auth_method, project,dataset,table : 데이타를 저장한 bigquery의 project,dataset,table 명을 정한다. 그리고 auth_method를 통해서 인증 방법을 설정하는데, 일반적으로는 service account에 대한 json 파일을 사용하는데, 여기서는 구글 클라우드내에 VM을 생성하였고, 앞에서 VM 생성시에 Bigquery에 대한 접근 권한을 이미 주었기 때문에, 인증 방식을 compute_engine으로 설정하면 된다.

  • flush_interval 은 어떤 주기로 버퍼된 데이타를 bigquery로 저장할것인지를 정한다. 여기서는 1초 단위로 저장하도록 하였다.

  • 그리고 중요한것중 하나가 schema_path 인데, 저장하고자 하는 bigquery 테이블의 스키마이다. 앞에서 테이블 생성에서 사용한 https://gist.github.com/Salinger/ef39b81ad2c48516b596 에서 다운 받았던 *.json으로 정의된 스키마 파일의 경로를 지정해주면 된다.

실행하기

모든 설정이 끝났으면

%sudo /etc/init.d/td-agent restart

명령을 이용해서 tdagent를 재기동하자.

그리고 빅쿼리 콘솔에서 “select count(*) from 테이블명” 명령을 사용하면 아래와 같이 카운트 수가 매번 올라가면서 데이타가 저장되는 것을 확인할 수 있다.


Datalab으로 대쉬보드 만들기

datalab은 오픈소스 iPython note의 구글 클라우드 버전이다. 자동으로 구글 클라우드 내의 앱앤진 내에 설치해주고, 구글 클라우드의 빅데이타 인프라 (빅쿼리등)과 손쉽게 연동되며, 구글 차트를 내장하고 있어서 그래프도 손쉽게 그려줄 수 있다.


데이타랩 준비하기

데이타랩을 사용하기 위해서는 https://datalab.cloud.google.com/ 에 접속하고, 로그인을 하면 다음과 같이 프로젝트를 선택하는 화면이 나온다.


만약에 아직 데이타랩을 설치 하지 않았으면 가운데 Deploy 버튼만 활성화가 된다. Deploy 버튼을 누르면 자동으로 데이타랩이 설치된다. 설치가 끝나면 Start 버튼이 활성화 된다. Start 버튼을 누르면 데이타 랩으로 들어갈 수 있다.

새로운 노트 만들기

다음은 데이타랩의 초기화면이다.


우리는 여기서, 새로운 노트를 만들어서 앞서 빅쿼리로 읽어드린 데이타를  lang(언어)별로 그룹핑을 해서 카운트하는 쿼리를 실행하고, 그 결과를 그래프로 만들것이다.

위의 초기화면에서 “+Notebook” 버튼을 눌려서 새로운 노트북을 만들어보자


노트화면이 로딩되었으면 상단의 메뉴를 보자


+Add code와, +Add Markdown 버튼을 볼 수 있는데,  Add Code는 파이썬이나 SQL과 같은 프로그래밍 언어를 정의하고 실행할 수 있는 공간이고, +Add Markdown은 일반적인 텍스트나 이미지를 통해서 간단한 글을 쓸 수 있는 공간을 만들어준다.

이렇게 코드써가면서 직접 실행해보고 그 결과를 확인하면서 그에 대한 내용을 설명하는 내용을 Markdown으로 작성하는 것과 같이 마치 노트에 계산을 해나가는 것처럼 써 나가기 때문에 이런 류의 프로그램을 노트북이라고 한다. (유사한 프로그램으로는 zeppelin 등이 있다 https://zeppelin.apache.org/)

쿼리 실행하기

그러면 Add code를 통해서 코드 섹션을 추가하고 SQL 문장을 추가해보자. 다음은 빅쿼리 트위터 테이블에서 lang 별로 그룹핑을 해서 카운트를 하는 SQL 문장이다.


이 문장을 실행하려면 노트북 상단의 “Run” 버튼을 누르면 된다.

다음과 같이 결과가 쿼리 바로 아래에 출력되는 것을 볼 수 있다.




그래프 그리기

다음으로 결과로 그래프를 그려보자

다음과 같이 두개의 코드 블럭을 추가하자


첫번째 코드 블럭에는 SQL 문장을 수행하는데 이때 --module twitter라고 정의를 해주면 결과가 twitter라는 모듈에 저장이 된다.

두번째 코드 블럭은 그래프를 그리기 위해서 chart 명령어를 이용하고 차트 타입은 pie로, 그래프의 x,y 축은 lang과, lang_count로 지정하고, 데이타 소스는  --date를 이용해서 앞의 쿼리 결과를 저장한 twitter로 지정한다.

다음으로 Run 버튼을 이용해서 쿼리를 수행해보면 다음과 같은 결과 화면을 얻을 수 있다.





지금까지 간략하게 Fluentd를 통해서 데이타를 수집하고 빅쿼리에 저장한 후, 데이타랩을 통해서 분석 및 리포팅을 하는 간단한 시나리오를 살펴보았다. fluentd나 데이타랩에 대한 사전적인 지식이 없었는데, 필자의 경우 이를 만드는데 대략 2시간의 시간이 소요되었다. 2시간의 시간으로 수 PB급의 빅데이타를 수집할 수 있고 분석할 수 있는 시스템을 구축할 수 있었다. 예전 같으면 하둡과 스팍 인스톨과 몇시간이 걸렸는데, 요즘 드는 생각은 빅데이타에 대한 접근 장벽이 많이 무너졌다고나 할까.

참고 자료


스파크 성능이 안나오면, 우리 회사 데이타팀 팀장왈. 먼저 파이썬으로 짰는지 확인 부터 해보라길래, 파이썬과 스칼라로 만들어진 스파크 성능 차이가 얼마나 나는지 찾아봤더니 다음과 같은 수치가 나왔다.


http://emptypipes.org/2015/01/17/python-vs-scala-vs-spark/ (원본 출처)


일단 스파크를 할려면 스칼라는 필수인듯 하다. 

간단한 프로토타입핑등에는 파이썬을 사용할 수 있겠지만 결국 프로적션은 스칼라로 최적화해야 할듯.

근데. 자바대 스칼라 성능 비교는 없네

머신 러닝 프레임웍에 대한 간단 정리


머신 러닝을 다시 시작해서 보다 보니 어떤 언어로 개발을 해야 하는지 의문이 들어서 페이스북 Server Side architecture 그룹에 올렸더니, 좋은 정보가 많이 들어왔다.

Matalab이나 R과 같은 언어는 수학 라이브러리가 풍부해서, 주로 모델을 만들어서 시뮬레이션 하는데 많이 사용되고

Python이 수학 라이브러리가 풍부해서 그런지 ML 부분에서 많이 사용되는데, Production 까지 올라가는 경우는 잘 못본거 같고, 주로 Python으로 모델을 프로토타이핑 하는 수준으로 사용되는 것으로 보인다. 아직까지 자세히는 보지 못했지만, 자바의 Spark이나 Mahout과 같은 분산 환경 지원성이 약하고, 언어의 특성상 다른 언어보다 성능이 떨어져서, 실제 Production은 다른 언어, 주로 자바를 많이 사용하는 듯 하다.


Python으로 ML을 하려면, numpy,matplot등 다양한 패키지를 설치해야 하는데, 이 경우 방화벽과 프록시가 있는 환경에서는 설치가 쉽지 않다. (몇시간을 무지 삽질했던 경험이.. Proxy를 설정해도 패키지 인스톨이 잘안되서)

Python의 경우 이런 주요 수학 라이브러리를 패키징해놓은 인스톨 패키징이 있는데

대표적으로 Continum의 아나콘다 http://continuum.io/downloads

http://www.scipy.org/ 등이 있다.

그리고 Python에서 많이 사용되는 ML 프레임웍으로는 http://scikit-learn.org/ 등이 있다.


각 언어별로 ML 지원 라이브러리와 사용 용도를 정리해놓은 글이 있다. https://github.com/josephmisiti/awesome-machine-learning


알고리즘을 직접 작성하는 경우가 대부분이겠지만, 왠만해서는 기존 알고리즘 보다 잘 만들기가 어렵기 때문에 기존 알고리즘을 잘 활용하거나 데이타 샘플링을 잘하거나 또는 구현 인프라를 최적화 하는 방안을 고려해볼 수 있겠고, 여러 알고리즘을 중첩 적용하여 조합 함으로써 좋은 결과를 이끌어내는 방법을 고려해볼 수 있겠다.
아울러 근래에는 클라우드에 ML 라이브러리를 제공하고 있기 때문에, Azure ML이나 IBM Watson등을 고려해볼 수 있다.

SSAG에서 관련된 몇가지 중요한 댓글 메모

하용호 참고로 애초에 분산환경을 활용하도록 만들어진 MLLib등을 제외하면, 자바든 C든 R이든 속도는 대동소이 합니다. 대부분 매트릭스 연산에 그쪽으로 최적화된 LAPACK이나 BLAS, 돈 좀 쓰면 MKL등의 라이브러를 가져다가 쓰게 되어 있어서요. 뭐랄까 다들 같은 육수집에서 육수 받아서 쓴다랄까. 파이썬 쓰세요 파이썬 ㅎㅎㅎ 으하핫

민경국 mvn clean package -DskipTests 가 문제없이 돌아가는 방화벽 상황이라면 제플린으로 스프크와 스파크ML 을 보시는 건 어떨지요?
mvn 명령 한방으로 제플린 + 스파크가 설치되니 학습하기 좋은것 같습니다.
...더 보기

서민구 R이 싫으면 파이썬이 좋은데 설치가 잘 안된다니 안타깝네요. Pandas, numpy, scipy, scikitlearn, nltk 정도만 있어도 좋은데요. 언어가 파이썬이라 개발자들이 쉽게 배우구요. 통계분석 라이브러리는 문서화가 미비하지만 scikitlearn 의 문서는 대단히 훌륭합니다.

KwangHo Yoon 몇년전에는 직접 구현하는 걸 선호했는데.. 지금은 python이나 R이 라이브러리가 너무 좋아서 저도 파이썬을 사용하고 있습니다. PredictionIO나 h2o를 사용하시면 hbase나 spark등의관리를 편하게 해주어서..대용량의 데이터를 처리할 때에도 머신 러닝에 더 집중하여 개발할 수 있습니다.h2o에도 위에서 말씀하신 제플린과 비슷한 h2o flow가 있는데..인터렉티브한 화면으로 예측 결과까지 제공합니다 https://www.youtube.com/watch?v=wzeuFfbW7WE



Numpy Install

빅데이타/머신러닝 | 2015.02.10 01:31 | Posted by 조대협

NumPy 설치 하기


파이썬으로 머신 러닝을 구현하기 위해서는 수학 라이브러리인 numpy가 필요하다

설치는 

http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy 에서 *.whl 파일을 다운로드 받은후

pip install numpy-1.9.2rc1+mkl-cp27-none-win_amd64.whl (64 비트 기준)

으로 설치 하면 된다.



설치후 확인을 위해서는 위와 같이 from numpy import * 를 한후에, random.rand(4,4)가 제대로 실행되는지 확인하자


참고

머신러닝이나 빅데이타 분석을 위해서는 NumPy 뿐만 아니라 matplot등 다양한 수학 모듈을 깔아야 하는데, 방화벽등이 있거나 하면 깔기가 매우 까다롭다. (의존성 관계도 복잡하고). 그래서 수학용 모듈을 모아 놓은 파이썬 인스톨패키지가 있다. http://www.scipy.org/install.html

처음부터 이걸로 까는게 시간을 절약할 수 있는 방법일듯

Vert.x 노트

클라우드 컴퓨팅 & NoSQL/Vert.x & Node.js | 2014.01.24 23:25 | Posted by 조대협

1. vert.x를 다운받아서 설치

2. Python을 사용하기 위해서 Jython 을 설치

- Jython 인스톨 방법은

% java -jar jython_installer-2.5.2.jar 


환경변수에 JYTHON_HOME을 Jython 인스톨 디렉토리로 설정


환경 준비 완료


3. 간단한 Python 테스트


※ Company Proxy로 인하여, Vertx 모듈이 설치가 되지 않는 경우. 


방법 1. 

Vertx는 module (라이브러리)를 외부 리포지토리로 부터 읽어와서 자동 설치 하는데,

회사 proxy 등을 사용할 경우 설치가 안되며, 이를 회피하기 위한 방법도 없다. 

방법은 간단한 웹서버를 로컬에 띄운후, mod.zip 파일을 그 디렉토리에 넣어야 한다.

이때 주의할점은 vertx는 repository의 80포트만 참조한다. (다른 포트로 띄우면 안된다).

가장 간단한 방법은 python -m SimpleHTTPServer 80 으로, 서버를 띄우는게 가장 쉽다.


C:\dev\tools\vert.x-1.3.0.final>bin\vertx run app.js -repo localhost

Attempting to install module vertx.web-server-v1.0 from http://localhost/vertx-mods/mods/vertx.web-server-v1.0/mod.zip

Downloading module...

Installing module into directory 'mods'

Module vertx.web-server-v1.0 successfully installed


아니면 직접 mod.zip 을 다운로드 받아서

{Vertx가 설치된 디렉토리}/mods/{모듈명}/ 아래에 압축을 풀어놓아도 된다.

Python이나 Javascript등에 필요한 모듈은 /mods가 아니라 sys-mods/ 아래에 깔아야 한다. 


방법 2. 

다른 방법 http://jcenter.bintray.com/ 에 들어가서 패키지를 찾아서 다운 로드 받은 후에

local maven repository안에 복사해놓는다. C:\Users\bw.cho\.m2\repository\io\vertx\lang-rhino\2.0.0-final

io.vertx~lang-jython~2.0.0-final 의 경우 C:\Users\bw.cho\.m2\repository\io\vertx\lang-jython\2.0.0-final에 lang-jython-2.0.0-final-mod.zip 파일만 복사




4. 로그 확인

로그는 시스템 디폴트 temp 디렉토리 아래 vertx.log로 생긴다.

$VERTX_HOME/conf/loggng.conf 에서 로그 위치 정의 가능

윈도우에서는 %TEMP%\vertx.log 에 생김


 


노트

- Vertx는 내부적으로 in-memory grid인 hazlecast를 사용. 이말은 즉슨 클러스터링에서 멀티 인스턴스 환경에서도 상태 공유가 가능하다는 이야기. 이를 통해서 내부적으로 BUS라는 것을 사용하는 것 같음

- 모듈이 제대로 설치되었는지 확인해보려면, vertx runmod을 이용해서 확인한다.

예) vertx runmod vertx.web-server-v1.0

- 레파지토리로 mvn 레파지토리 사용이 가능함. 레파지토리 경로는 $VERTX_HOME/conf/repo.txt에 지정됨


주의 : 인터넷에 떠돌아 다니는 예제가 1.x 등 예전 버전일 경우가 많음. 샘플코드가 안맞는 경우가 많으니 반드시 버전 확인하고 수행 바람. 





import pika
import ast
import pymongo
import datetime
import logging
import time
import sys,traceback,socket,threading
from datetime import datetime
from time import sleep

# configuration
MONGODB_NAME = "terrydb"
HOSTNAME = ':'+socket.gethostname()
QUEUE_NAME = 'hello'
MONGODB_URL= 'mongodb://localhost'
RABBITMQ_URL='localhost'

LOG_FORMAT = ('[%(levelname)s] %(asctime)s %(name)s : %(message)s')
LOGGER = logging.getLogger(__name__)
              
class WorkerThread(threading.Thread):
    def __init__(self,threadID,name,counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
        # init rabbitmq
        # init mongodb

    # make rabbitMQ connection and create channel
    def initRabbitMQ(self):
        self.q_conn = pika.BlockingConnection(pika.ConnectionParameters(host=RABBITMQ_URL))
        self.q_channel =self.q_conn.channel()
        self.q_channel.queue_declare(queue=QUEUE_NAME) # create queue
    
    # make mongo db connection
    def initMongoDB(self):
        self.mongo_conn = pymongo.MongoClient(MONGODB_URL)
        self.mongo_db = self.mongo_conn[MONGODB_NAME]

    def onMessage(self,ch,method,properties,body):
        try:
            LOGGER.info(str(self.name)+" recevied "+body)
            #print str(self.name) + "[x] recevied %r" % (body,)
            json_dict = ast.literal_eval(body) # convert string to dictionary
            ## need to be fixed
            ## specify board name here
            self.writeToMongoDB('MYBOARD',json_dict)
        except ValueError:
            print 'String parsing error'
        except:
            print 'unknown error'
            traceback.print_exc(file=sys.stdout)
    
    def writeToMongoDB(self,boardname,post):
        # get board name
        s = self.mongo_db[boardname]
        # generate uuid for the posting
        post['_id'] = self.genPostId()
        try:
            s.insert(post)
        except:
            LOGGER.error(" mongodb insert fail" + str(sys.exc_info()[0]) )
            traceback.print_exc(file=sys.stdout)

    # generate post unique id with
    # format : YYMM{microsecond from this month 1}:{hostname}
    def genPostId(self):
        time.sleep(0.001) # intentionally sleep to remove key duplication
        dt = datetime.now()
        year = str(dt.year)[-2:]
        mon = dt.month
        if mon < 10 :
            mon = '0'+str(mon)
        else:
            mon = str(mon)
        print dt.second
        print dt.microsecond
        uid = year+mon+ str ( int(dt.day * 24 * 60 * 60 + dt.second) * 1000 + dt.microsecond / 1000.0)
        uid = uid + HOSTNAME
        return uid
                
    def run(self):
        LOGGER.info(str(self.name)+" has been started")
        self.initRabbitMQ()
        self.initMongoDB()
        self.q_channel.basic_consume(self.onMessage,queue=QUEUE_NAME,no_ack=True)
        self.q_channel.start_consuming()
        #while 1:
        # time.sleep(0.01)


         
    #savePostToDB('helloboard',j)
                    

def print_usage():
    print 'usage : python worker_multithread {number of thread}'
    exit()
    
def main(argv):
    if len(argv) <2:
        print_usage()
    if argv[1].isdigit() ==False :
        print_usage()
    max_thread = int(argv[1])
    logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
    
    LOGGER.info('Create '+str(max_thread)+' threads ')

    threadList =[]
    for i in range(max_thread):
        t_name = "WorkerThread-"+str(i)
        t = WorkerThread(i,t_name,i)
        t.start()
        threadList.append(t)
    
if __name__ == '__main__':
    main(sys.argv)


Python 공부 노트 11. Class

프로그래밍/Python | 2014.01.03 00:33 | Posted by 조대협


class 클래스명(ParentClass명):

  def __init__(self,인자....) # 생성자임

    ParentClass명.__init__(self) # 부모 생성자를 불러줌

  

 def mymethod(self): # 모든 메서드에는 "self"를 인자로 받아야함

    self.myname = 'terry'  # 클래스내의 내부 변수는 self로 시작함


 def call(self):

   self.mymethod() # 다른 내부 메서드를 부를때에는 self.method 명으로 불러야함

Python에서 Open API 호출하기

프로그래밍/Python | 2013.11.22 19:09 | Posted by 조대협

Rest API를 호출하기

여러가지 라이브러리 (urllib2, httplib2)등을 체크해봤으나, https 를 가장 쉽게 호출할 수 있고, 사용하기 편한것은 requests라는 것이 가장 편리함 http://www.python-requests.org/en/latest/user/quickstart/#make-a-request 에서 curl 로 다운로드 하고 설치해서 사용



위는 도스창을 이용해서 간단하게 https로 dna.daum.net을 호출한 코드인데, 리턴값이 한글이라서 그런지. cp949 encode 에러가 남. (이건 나중에 수정해야 할거 같고)


기타 참고 자료 (아래)


참고 : API 호출 하기

https://dna.daum.net/tools/python/tutorial


SSL 사용하기

urllib2는 https가 지원되지 않음


1. Python 인스톨본이 SSL을 지원해야 한다.

. 확인하는법

>>> import socket

>>> socket.ssl

<function ssl at 0x4038b0>


2. httplib2 설치

https://code.google.com/p/httplib2/



'프로그래밍 > Python' 카테고리의 다른 글

Python 공부 노트 11. Class  (0) 2014.01.03
Python 공부 노트 11. Module install  (0) 2014.01.02
Python에서 Open API 호출하기  (0) 2013.11.22
Django에서 static file (css,img 사용하기)  (0) 2013.11.21
Django Template  (0) 2013.11.21
Django Hello World  (0) 2013.11.21

Django Template

프로그래밍/Python | 2013.11.21 02:07 | Posted by 조대협


Django의 MVC 구조


원본- littlegreenriver.com

Template 란?


Template은 쉽게 이야기 하면 jsp 파일과 같다고 보면된다.

template은 string으로 파일에서 로딩할 수 도 있고 몇개의 notation을 통해서 구성된다.

마치 JSP의 <% %> 처럼

time.html 파일이 다음과 같을때 

current time is {{ current_time }}


이는 

current time is <%=current_time%> (JSP에서)와 같은 의미라고 보면된다.

실제 view 모듈에서 이 템플릿을 렌더링 하는데, 이때, tempalte에 있는 인자들을 대입한다.

    template = loader.get_template('time.html')

    current_time = datetime.datetime.now()

    context = Context({'current_time' : current_time })

    return HttpResponse(template.render(context))


Context 객체는 인자를 넘기는 일종의 컨테이너라고 보면되고,

Template에 정해진 변수 이름에, 실제 값을 맵핑 시킨후에,

Template을 이 Context로 렌더링 한다.



Template 위치에 대해서.


https://docs.djangoproject.com/en/1.4/ref/templates/api/#loader-types

django.template.loaders.app_directories.Loader

Loads templates from Django apps on the filesystem. For each app in INSTALLED_APPS, the loader looks for a templates subdirectory. If the directory exists, Django looks for templates in there.


This means you can store templates with your individual apps. This also makes it easy to distribute Django apps with default templates.


템플릿을 로딩하는 방법은 여러가지 Loader 설정에 따라 변경할 수 가 있는데,

그중에서 filesystemLoader와 app_directories.loader가 디폴트 설정되어 있다.

이때, app_directories.loaderㅢ 경우에는 app directory 아래의 /templates/ 디렉토리에서 template을 찾는다.


#views.py - mysite/reader/views.py

from django.http import HttpResponse

from django.template  import Context, loader

import datetime



def what_time_is_it(request):

    template = loader.get_template('time.html')

    current_time = datetime.datetime.now()

    context = Context({'current_time' : current_time })

    return HttpResponse(template.render(context))


이파일은 mysite라는 프로젝트의 reader라는 애플리케이션이다.

위의 파일 경로가 mysite/reader/views.py 이다

template의 파일명만 지정했는데, 이 경우

mysite/reader/templates/time.html을 찾게 된다.


Template 사용시 Dictionary 접근 방법

JSON을 변환하여 dictionary를 접근하면, 일반 python code에서

item['name']['firstname'] 이었다면

Template에서는 item.name.firstname 으로 해야 한다.


참고 : https://docs.djangoproject.com/en/1.4/ref/templates/api/#loader-types



Python을 이용한 간단한 mongodb insert 예제


1. easy_install.exe를 이용하여, mongodb python driver인 pymongo를 설치


2. 코드 작성

 connection얻고, db선택하고,collection(여기서는 users테이블) 선택하면되고,

 insert,update등은 기존 mongodb script와 유사함. 에러 처리는 아래와 같이 try,except 사용

import sys

import pymongo

 

connection = pymongo.MongoClient("mongodb://localhost")

db = connection.terrydb

users = db.users

 

doc = {'_id':'myid','firstname':'Terry','lastname':'Cho'}

 

try:

    users.insert(doc)

except:

     print "insert failed",sys.exc_info()[0]

 

 

3. insert 확인



초경량 Python 웹서버 bottle

MVC 예제


Controller 파일 구현 

/controller.py

import bottle

 

mythings = ['apple','orange','banana','peach']

 

@bottle.route('/')

def home_page():

    fruit = bottle.request.get_cookie("fruit")

    return bottle.template("hello_world",username="Andrew",things=mythings,like=fruit)

               

@bottle.post('/favorite_fruits')

def favorite_fruits():

    fruit = bottle.request.forms.get('fruit')

    if(fruit == None or fruit==""):

        fruit="No Fruit Selected"

    bottle.response.set_cookie('fruit',fruit)

    return bottle.template("fruit.tpl",{'fruit':fruit})

 

bottle.debug(True)

bottle.run(host='localhost',port=8080)


 

TBL 파일들은 템플릿으로, Python 변수는 {{ }}로 표현 (cf. jsp에서 <%=xx %>)

파이썬 로직은 %로 표현 (cf. jsp에서 <% %>)


/hello_world.tpl

<html>

<body>

Welcome {{username}}<br/>

You like <b>{{like}}</b>

<p>

<ul>

%for thing in things:

<li>{{thing}}</li>

%end

</ul>

<form action="/favorite_fruits" method=POST>

    What fruit do you like ?

    <input type="text" name="fruit" size=20 value="">

    <input type="submit" value="submit">

</form>

</body>

</html>


/fruit.tpl

<body>

Your like {{fruit}}

</body> 


실행 예




 



Bottle은 Python 기반의 초경량 웹서버이다.

Python 쪽에서는 Django등을 많이 사용하고 있지만, 설치도 쉽고, 가볍고 해서, 특정 목적이나 가벼운 테스트 웹 애플리케이션 개발등에는 충분히 활용이 가능하다.

(자바의 Jetty 와 같은 느낌?)


1. easy_installer에 설치

먼저 bottle을 설치하려면, installer부터 설치하는 것이 수월하다. python은 linux의 yum이나 rpm , 또는 Java의 maven과 유사하게 Pypi(Python Package Index - https://pypi.python.org/pypi ) 라는 툴을 제공한다. 


먼저 https://pypi.python.org/pypi/setuptools#windows 에서 ez_setup.py를 다운로드 받아서 실행한다



실행이 끝나면 ${Python 설치디렉토리}/Scripts/easy_install.exe 가 설치 된다.


2. bottle 설치

easy_install bottle 을 실행하면 bottle 라이브러리가 설치된다.



3. 간단한 애플리케이션 제작

bottle이 설치되었으면 간단한 애플리케이션을 만들어보자

아래 hello_world.py


import bottle

 

@bottle.route('/')

def home_page():

    return "hello world\n"

 

@bottle.route('/testpage')

def test_page():

    return "this is test page"

 

bottle.debug(True)

bottle.run(host='localhost',port=8080)


4. 실행

%python hello_world.py



다음으로 브라우져에서 http://localhost:8080/testpage 로 접근하면 다음과 같은 결과를 얻을 수 있다.



Python Fabric Install

프로그래밍/Python | 2013.01.28 18:55 | Posted by 조대협

AWS EC2 (Amazon Linux 기준)


1. Python install (dev package로 설치)

(반드시 dev package가 설치되어 있어야지, pycrypto 설치시 에러가 나지 않음. pycrptyo는 encryption 관련 라이브러리로 C 라이브러리를 사용하는데, 컴파일중, python.h를 사용한다. 이 헤더 파일은 dev package안에 포함되어 있음)


- yum install python-devel 


2. pip install

$ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py

$ [sudo] python get-pip.py


3. gcc가 인스톨 (pycrypto 설치를 위해서 필요함) 

yum install gcc


4. fabric install


pip install pycrypto fabric


5. 설치 확인


from fabric.api import run


def host_type():

    run('uname -s')


Admin 메뉴 추가 하기

setting.py에서

- admin 항목 uncomment 처리. INSTALLED_APPS에서 admin 모듈을 uncomment 처리하면됨

- 다음으로 manage.py에서 syncdb 처리 (app이 새로 등록되었으니 데이타 베이스 테이블 생성)


urls.py에서 

- admin url을 오픈해주기 위해서 admin 기능 관련 코드 uncomment 처리


그후 django 서버 기동하고 http://xxxx//admin 으로 로그인 하면됨.

로그인시 id/passwd는 처음에 manage.py syncdb 할때 넣었던 값으로 함.

이 admin 화면에서는 사용자 관리, 그룹 관리, 권한 관리등의 기본적인 기능들을 제공한다.


Admin 메뉴에 App admin 기능 추가 하기

django는 기본적으로 admin 기능을 제공하는데, 이 admin 기능에서는 해당 app의 model을 기반으로 UI를 자동 생성해준다.

예를 들어 poll(설문조사) 애플리케이션에서 Poll Model Class를 생성 관리할 수 있는 UI를 자동으로 만들어준다.

- ${app}디렉토리 아래 admin.py를 만들고

- 안에 다음과 같이 admin에 해당 Model 객체를 등록해주면 된다.


from polls.models import Poll

from django.contrib import admin


admin.site.register(Poll)


그러면 해당 Model 객체의 생성자 필드를 채울 수 있는 UI가 자동으로 생성된다.

그 밖에, 해당 Model의 값을 List 형식으로 출력될때 필드를 정하거나, Filtering등의 기능을 정의할 수 있고, Model의 attribute 뿐만 아니라, Model에서 사용자가 구현한 method의 결과값을 출력하게 할 수 도 있다.






※ 주로 모델 객체의 값에 대한 CRUD 기능을 위주로, Admin 기능을 구성할 수 있게 되어 있다.


Django는 기본적으로 MVC 모델을 가지고 있고, DB 접근에 대해서는 OR Mapper와 같은 기능을 model 기능을 이용해서 제공한다.  

사실 최적화 정도는 조금 고려해봐야 겠지만, 기본적인 사용 방법은 다음과 같다.


==

python manage.py syncdb

- setting.py를 참고로 하여, default table을 데이타베이스에 생성


python startapp {appname}

- 새로운 app을 생성함. 

- 생성후에는 setting.py에 가서, INSTALLED_APPS 부분에 생성한 app이름을 넣어줘야 컨테이너가 인식함

INSTALLED_APPS = (

   'django.contrib.auth',

   'django.contrib.contenttypes',

   'django.contrib.sessions',

   'django.contrib.sites',

   'django.contrib.messages',

   'django.contrib.staticfiles',

   # Uncomment the next line to enable the admin:

   # 'django.contrib.admin',

   # Uncomment the next line to enable admin documentation:

   # 'django.contrib.admindocs',

   'polls' <-- 요렇게 추가

)

- models.py 파일에 데이타 클래스를 정의

  Value Object을 정의하는데, Java와는 다르게, Data Type이나 객체간 relationship도 지정함

  

class Choice(models.Model):

    poll = models.ForeignKey(Poll) <-- Poll Class에 대한 FK

    choice = models.CharField(max_length=200) <-- varchar(200)

    votes = models.IntegerField() <-- Int type

    

- 마지막으로 model.py sql {appname} 해주면, 해당 DBMS에 테이블을 생성 SQL문을 만들어서 보여줌 (실제 실행은 안됨)

  테이블명은 {appname}_{modelclass명} 식으로 생성됨

  예를 들어 appname이 polls이고, VO가 위에 클래스 명처럼 Choice일 경우 테이블은 아래와 같은 형태로 생성됨

  CREATE TABLE "polls_choice" (

    "id" integer NOT NULL PRIMARY KEY,

    "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"),

    "choice" varchar(200) NOT NULL,

    "votes" integer NOT NULL

  );

  테이블명과 Index등의 생성 규칙

The exact output will vary depending on the database you are using.

Table names are automatically generated by combining the name of the app (polls) and the lowercase name of the model -- poll and choice. (You can override this behavior.)

Primary keys (IDs) are added automatically. (You can override this, too.)

By convention, Django appends "_id" to the foreign key field name. (Yes, you can override this, as well.)

The foreign key relationship is made explicit by a REFERENCES statement.

It's tailored to the database you're using, so database-specific field types such as auto_increment (MySQL), serial (PostgreSQL), or integer primary key (SQLite) are handled for you automatically. Same goes for quoting of field names -- e.g., using double quotes or single quotes. The author of this tutorial runs PostgreSQL, so the example output is in PostgreSQL syntax.

The sql command doesn't actually run the SQL in your database - it just prints it to the screen so that you can see what SQL Django thinks is required. If you wanted to, you could copy and paste this SQL into your database prompt. However, as we will see shortly, Django provides an easier way of committing the SQL to the database.


- insert는 객체를 만든후에, object.save()를 하면됨

- select는 {ClassName}.objects.get({key}={value}) 를 하면 select x from ClassName where {key}={value} 와 같은 효과

  {ClassName}.objects.filter 하면 조건 검색

- 해당 object.delete() 하면 삭제


reference https://docs.djangoproject.com/en/1.4/intro/tutorial01/