2016년 1월 9일 토요일

들쑥날쑥한 데이터 히스토그램 그리기

본문은 80만개가 넘는 들쭉날쭉 데이터에 도수 분포를 그릴때 만나는 문제와 대처방안을 다룬다.

먼저 80만개의 데이터를 플롯 했다.


평균(mean) : 176.8 , 중앙값(Median) 28 이다.

다음은 히스토그램이다.


도수 분포가 편중되어 성질을 파악하기 어렵다.
3분위 값이 114임을 감안할때 큰 값들을 가차 없이 눌러야 적절한 플롯이 나온다.

로그를 이용해서 튀는 값들을 눌러 보았다.


측정 값들이 크지 않아서 로그의 밑수(base number)를 1.1 정도로 잡았다.

그리고 히스토그램이다.


20 ~ 50 사이의 빈도가 높다.
측정 치로 볼때, 6 ~ 117의 사이의 값이다.



참고

판다스 사용 코드 모음
# 평균 값
stone.mean()
# 분위 값
stone.quantile([.25,.5,.75])
# ggplot 스타일의 플롯
with plt.style.context(('ggplot')):
    stone.plot()
# 히스토그램 bins 지정
stone.hist(bins=30)
# 로그 적용
cristal = stone.applymap(lambda i: math.log(i,1.1))
# ggplot 스타일에 y 라벨 추가
with plt.style.context(('ggplot')):
    ax = cristal.plot()
    ax.set_ylabel('log')
# 거듭제곱를 통한 측정치 구간
"%d ~ %d" % (pow(1.1,20),pow(1.1,50))

히스토그램 (  histogram )
도수분포를 정보 그림으로 나타내는 한 가지 방법이다.

도수분포
범주(계급)을 나누고 각 범주에 속하는 측정치의 수를 도수라 한다.
도수의 흩어짐 정도를 분포라 하고, 표나 그림(도)를 통해서 표현한다.

2016년 1월 8일 금요일

네이버 뉴스 관심도 보기

뉴스에 피드백(댓글)은 사람들의 능동적인 관심을 볼 수 있다.
본글은 연도별 네이버에 대한 관심과 섹션(분야) 비중을 다루었다.

1. 연도별 네이버 관심도

뉴스 댓글수수집 기사수
2004235145963
20051768871582
2006395449972764
2007590529673747
2008641619669141
2009107011974783
2010109192175476
2011141264275527
2012985043776212
20132254274476045
20142811589376015
20152504893276461

수집된 기사 수 차이는 전체적인 동향을 보는데 있어 무난한 것으로 간주한다.
뉴스 댓글은 2009년에 아웃링크 방식으로 변경된 이후 3년간 외면 받다가,
뉴스스탠드 서비스로 개편 되면서 다시 살아 났다.

2. 연도별 섹션 관심 비중

경제과학문화사회세계스포츠정치
20041422632974699910189
200525833462955155588340740
200642453032569841277312888866237750878837
20076036754841087194881828405118797601081644
2008931364464746565613227938151380801661284
200986563108356119497291722769520387029
201012328211278279906266858890640420029
20111584531878231290303467981328790457659
20128130791164445859010300712164638603360396
20132236418205910324868257215832177936806765198
20143247132239835027918689824143228008107574319
20153520920152747522072308617260236726806808779

사회, 정치는 항상 뜨거운 감자다.
이외에 과학, 문화와 반대로 경제 쪽에 관심이 높아지고 있다.
아쉽게도 스포츠 섹션은 댓글 수에 대한 파싱(parsing)에 실패했다.


표지 사진

2016년 1월 7일 목요일

네이버 뉴스 출처 성향 보기

네이버의 10년간 TOP 뉴스를 대상으로 각 출처에 대한 성향을 조사했다.
 - TOP 뉴스는 하루 기준으로 섹션(7) * 탑(30) = 210개가 발생된다.
 - 총 296개의 출처가 있었고, 섹션 중에 하나가 최소 100건 이상만 선별했다.

2016년 1월 5일 화요일

기상청 날씨 API 개선방안

 기상청 날씨 서비스를 위한 성능 개선 방안을 다룬다.


먼저 기본적인 사용 방법이다.


1. “위/경도” 또는 “지명 이름”를 “격좌 좌표”로 변한
2. “격좌 좌표”를 기상청 API에 조회 (날씨)

조회가 발생할 때마다 기상청 API를 호출하는 것은 비효율적이다.


다음은 성능 개선 방안이다.


1. “지역 이름”에 해당하는 “날씨 정보”를 일괄 수집한다. (총 3772, 시단위 84)
=> 수집된 데이터는 “지역 이름”, “위/경도”, “격자 좌표”,  “날씨 정보” 속성을 가진다.
2. 위/경도를 역지오코딩으로 “지역 이름”을 추출한다.
3. “지역 이름”에 해당되는 “날씨 정보”를 반환한다.



만들어 놓은 것만 쓰다보니 그림과 같은 1차 발상을 한다.
역지오코딩을 통해 "지역 이름"을 추출하는 것이 API 서비스를 통해서 다음/네이버에서 제공된다. 속도가 느린 것이 당연한 API 서비스다.!!

더 낳은 방안을 찾다.


날씨에 중요한 건 “지역 이름”이 아니라 관측 장소와 거리이다.
“위/경도” 좌표 기준으로 최단 거리에 해당하는 지역의 "날씨 정보"를 반환하자.

최단 거리는 min() 구하는 로직이라 시간 복잡도 O(n)으로 충분하다.

사무실에 가만히 공상하는 것이 낯선 환경에서는 생각은 짧고 손은 분주하다.


검증을 위해 구현한 예제 코드이다.

import pandas as pd
import sqlite3
conn = sqlite3.connect('kma.db')
df = pd.read_sql('select * from loc_map_book',con=conn)

df = df [ df['lev3'] == '-' ]
df['city'] = df['lev2'].apply(lambda i: i[-1] == '시' or i[-1] == '-')
TPS = df[ df['city'] ].to_dict(orient = 'records')

df.head(3)
OUT>>

lev1
lev2
lev3
nx
ny
lon
lat
city
0
서울특별시
-
-
60
127
126.980008
37.563569
TRUE
1
서울특별시
종로구
-
60
127
126.981642
37.570378
FALSE
19
서울특별시
중구
-
60
127
126.999642
37.561003
FALSE

def closest_pair(lon,lat):
    _min_dist = pow(TPS[0]['lon'] - lon, 2) + pow(TPS[0]['lat'] - lat, 2)
    
    for tp in TPS[1:]:
        _cur_dist = pow( tp['lon'] - lon,2 ) + pow( tp['lat'] - lat, 2 )
        
        if _cur_dist < _min_dist:
            _min_dist = _cur_dist
            _out_pair = tp
    
    return _out_pair

closest_pair(132,37) # 울릉도
OUT>>
{'city': True,
 'lat': 37.44708611111111,
 'lev1': '강원도',
 'lev2': '삼척시',
 'lev3': '-',
 'lon': 129.16748888888887,
 'nx': 98,
 'ny': 125}

울릉도의 경우 가장 가까운 "강원도 삼척시"가 나온다.



웹 서비스의 논리적인 구조

프로그래머와 의사 소통을 위해서 수만은 솔루션들을 기억 할 수는 없었다.
비 프로그래머 입장에서는 논리적인 구조를 통해서 대화를 풀어보자.

본문은 웹 서비스의 논리적인 계층에 대한 이해를 목표로 한다.
각 계층를 대변하는 솔루션들은 그들 중의 하나로 예기 할 수 있을 것이다.

프로그래머가 바라보는 웹 구조는 어떨까?

프로그래머 관점에서 보는 레이어(계층) 구조이다.




파이썬 Flask 웹 프레임워크의 구조 예제이다.
Presentation Layer : Jinja
Business Layer : flask
Data Access Layer : SQLAlchemy
Persistence Layer : py-postgresql

중요한 것은 데이터를 다루는 일이다.




잘 만들어진 아키 그림은 코멘트가 가비지 일 수 있다.
읽지 않고 보는 것으로 충분해 보인다.

References

이미지 조회
http://www.teradatamagazine.com/v09n01/Tech2Tech/DAOs-enable-active-integration/

2015년 12월 30일 수요일

구글 API 서비스 사용 퀵가이드

구글의 어마무시한 서비스 API를 사용하는 퀵가이드를 다룬다.
요약하면 다음과 같다.

1. 관리 콘솔을 통한 인증 정보 발급 받기
2. 프로그램 언어 및 사용 방법에 따른 인증
3. 서비스 API 사용 가이드에 따른 개발

Google Developer Console

구글 개발을 위한 관리 콘솔

1. 프로젝트 생성

2. 사용자 인증 정보 생성

API 키
 - API 호출시 사용할 토큰을 발급한다.
OAuth 2.0 클라이언트 ID
 - 인증 정보가 있는 client_secrets.json을 다운로드 한다.

API Client Library for Python

파이썬을 위한 API 클라이언트 가이드

3. 설치형 어플리케이션을 위한 OAuth 2.0 인증 예제

import webbrowser
import httplib2

from apiclient import discovery
from oauth2client import client

flow = client.flow_from_clientsecrets(
        'client_secrets.json',
        scope='https://www.googleapis.com/auth/blogger.readonly',
        redirect_uri='urn:ietf:wg:oauth:2.0:oob')

auth_uri = flow.step1_get_authorize_url()
webbrowser.open(auth_uri)

# Python 2.x raw_input()
auth_code = input('Enter the auth code: ')

credentials = flow.step2_exchange(auth_code)
http_auth = credentials.authorize(httplib2.Http())

blogger_service = discovery.build('blogger', 'v3', http=http_auth)
blogger_service.users().get(userId='self').execute()

OUTPUT >>
{'about': '',
 'blogs': {'selfLink': 'https://www.googleapis.com/blogger/v3/users/g107745812829425907154/blogs'},
 'displayName': '김주훈',
 'id': 'g107745812829425907154',
 'kind': 'blogger#user',
 'selfLink': 'https://www.googleapis.com/blogger/v3/users/g107745812829425907154',
 'url': 'https://www.blogger.com/profile/14043740031094632533'}


References

구글 개발 콘솔
https://console.developers.google.com

구글 API 탐색
https://developers.google.com/apis-explorer/

구글 Python 클라이언트 라이브러리 가이드
https://developers.google.com/api-client-library/python/