python 및 머신러닝/집단지성 프로그래밍
[Programming Collective Intelligence] - 집단지성 프로그래밍 3장 군집발견
by java개발자
2015. 8. 24.
# -*- coding: utf-8 -*-
from myutil import consolePrintWithLineNumber as c
'''
Created on 2015. 8. 24.
@author: Administrator
'''
# 3장 군집발견
# 56p
# 3-2 단어 벡터 (자료수집)
'''
http://kiwitobes.com/clusters/blogdata.txt 링크는 깨졌다-_-;
http://kiwitobes.com/clusters/feedlist.txt 링크도 깨졌다.
> 저자의 원본소스파일 안에서 찾을 수 있음
'''
import feedparser
import re
# rss url을 분석해서 단어별 출현횟수를 딕셔너리로 출력한다.
def getwordcounts(url):
d = feedparser.parse(url)
wc = {}
for e in d.entries:
if 'summary' in e:
summary = e.summary
else:
summary = e.description
words = getwords(e.title + ' ' + summary)
for word in words:
wc.setdefault(word, 0) # wc에 word가 없는 경우만 0으로 하는 것 같다.
wc[word] += 1
return d.feed.title, wc
#
def getwords(html):
txt = re.compile(r'<[^>]+>').sub('', html) # HTML tags 삭제
# words = re.compile(r'[^A-Z^a-z]+').split(txt) # 알파벳 이외의 문자(공백, 특수문자 등등)로 자르기. 헉!! 한글은...???
words = re.compile(r'[^A-Z^a-z^ㄱ-ㅎ^ㅏ-ㅣ^가-힣]+').split(txt) # 한글도 단어에 포함할 수 있도록 하기!!!
return [word.lower() for word in words if word != '']
# c(getwordcounts('http://radar.oreilly.com/index.rdf')) # 성공!!
# c(getwordcounts('http://electro85.blog.me/220072783373')) # 일반적인 네이버 블로그는 실행하면 에러난다. > rss의 형식에 맞지 않나보다
'''
네이버 블로그는 /rss 를 붙이면 rss 로 조회가능 - 그런데 글 전체 내용이 나오지는 않는다.summary로...
http://electro85.blog.me/rss
http://electro85.blog.me/rss/1
http://electro85.blog.me/rss/atom
'''
# c(getwordcounts('http://electro85.blog.me/rss'))
# c(getwordcounts('http://blog.rss.naver.com/camping2172.xml'))
# 책의 소스와 조금 다르다.
def practice0(filename):
apcount = {}
wordcounts = {}
feedlist = [line for line in open(filename, 'r', encoding='UTF-8')]
testcount = 0;
for feedurl in feedlist:
# 테스트로 몇개만 해보자
if testcount > 5:
break;
testcount += 1
try:
title, wc = getwordcounts(feedurl)
wordcounts[title] = wc
for word, count in wc.items():
apcount.setdefault(word, 0)
if count > 0: # count 가 0인 경우는 없다. 항상 성립. (혹시나 스파스가 아닌 경우를 고려한 것인가??-코딩더매트릭스3장86p - 아이템이 없는 경우 0으로 출력한 것을 sparsity를 유지하지 않는 다고 말한다.)
apcount[word] += 1
c('Succeeded to parse feed %s' % feedurl)
except:
c('Failed to parse feed %s' % feedurl)
# 단어 빈도에 따라 제외 작업
wordlist = []
for w, bc in apcount.items():
# frac = float(bc) / len(feedlist)
frac = float(bc) / testcount # test한 개수만 사용하기 때문에
if frac > 0.1 and frac < 0.5:
wordlist.append(w)
# else:
# c(w + ' is not included. for ' + str(frac) + ' bc: ' + str(bc)) #단어 빈도 확인하기 위해
# 결과를 파일로 저장
# 처음 작동하면, 문서캐릭터셋이 MS949로 생성되어서 한글이 깨진다. -_-;; 직접 캐릭터셋을 바꿔주고 다시 하면 그 다음부터는 UTf-8이 유지된다. 이클립스에서 만들어서 그런가? 그러네.. 이클립스 프로젝트 캐릭터셋을 바꿔주면, 정상 동작
out = open('blogdata1.txt', 'w', encoding='UTF-8')
# 상단 첫줄 출력(단어 목록)
out.write('Blog')
for word in wordlist:
out.write('\t%s' % word)
out.write('\n')
# 두번째 줄부터 왼쪽에 블로그명, 오른쪽에 각 단어별 출현횟수
for blog, wc in wordcounts.items():
c(blog)
out.write(blog)
for word in wordlist:
if word in wc:
out.write('\t%d' % wc[word])
else:
out.write('\t0')
out.write('\n')
practice0('feedlist.txt')
'''
현재 블로그의 단어 빈도까지 포함해서 평균을 내는 것은 정확도가 떨어진다.
특정 단어의 출현이 다수 발생하는 이유가 the, she가 아니라 정말 그 블로그의 주제어 일 수 있기 때문에
단어 빈도에 따라 특정 단어를 제외하는 로직은
다음과 같이 정의 할 수 있다.
현재 블로그를 제외한 99개의 블로그에서 단어 리스트를 추출해서 다수 출현하는 단어 빈도를 조사.
현재 블로그의 단어빈도와 비교해서 제외
출처 : 머신러닝 인 액션
'''
77 > Succeeded to parse feed http://feeds.feedburner.com/37signals/beMH
77 > Succeeded to parse feed http://feeds.feedburner.com/blogspot/bRuz
79 > Failed to parse feed http://battellemedia.com/index.xml
77 > Succeeded to parse feed http://blog.guykawasaki.com/index.rdf
77 > Succeeded to parse feed http://blog.outer-court.com/rss.xml
77 > Succeeded to parse feed http://feeds.searchenginewatch.com/sewblog
101 > Eschaton
101 > Search Engine Watch
101 > Signal v. Noise
101 > Guy Kawasaki
101 > Google Blogoscoped