본문 바로가기
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