1. Collective Intelligence
Chapter 4. 검색과 랭킹
Kwang Woo Nam
Department of Computer and Information Engineering
Kunsan National University
Textbook: Programming in Collective Intelligence, Toby Segaran
2. 검색엔진
검색엔진이란
인터넷상에서 방대한 분량으로 흩어져 있는 자료를 가운데 원하는 정보를 쉽게 찾을 수
있도록 도와주는 소프트웨어
검색 방법의 종류
– 키워드 검색 : 사용자가 키워드, 즉 검색어를 직접 입력하는 검색
– 카데고리 검색 : 검색엔진이 제시한 몇 가지 항목들 가운데 사용자가 원하는 항목을 선택하는
방식으로 범위를 좁혀가는 검색
검색엔진의 종류
– 단어별 검색엔진(word-oriented searching):검색하고자 하는 내용을 입력하면,
검색사이트에 있는 데이터베이스를 찾아 웹페이지로 보여주는 검색엔진(Google)
– 주제별 검색엔진(subject-oriented searching):인터넷상에 있는 정보를 큰 범위에서 좁은
범위로 좁혀가며 찾는 방식의 검색엔진(Yahoo, Naver)
– 메타 검색엔진(Meta-search engine):인터넷에서 규모가 큰 검색엔진들에 사용자가 입력한
검색키워드에 대하여 의뢰한 뒤 결과를 가져오는 검색엔진
데이터마이닝 : Collective Intelligence 2
3. 검색엔진
검색엔진의 동작 순서
웹 크롤링(Web crawling)
– 웹 로봇
인덱싱(Indexing)
검색(Searching)
웹 크롤링 단계
The Web
Information Need
Formulation Indexing
Query Rep Inverted index and
검색 단계 인덱싱 단계
Ranking
Ranked List
web graph
Learning
User Relevance Feedback
Crawler
데이터마이닝 : Collective Intelligence 3
4. 검색엔진 : 웹로봇
웹 로봇의 정의
지정된 URL 리스트에서 시작하여 웹 문서를 수집하고, 수집된 웹 문서에 포함된 URL들의
추출과정과 새롭게 발견된 URL에 대한 웹 문서 수집 과정을 반복하는 소프트 웨어
– 웹 Web Robot, Spider, Crawler, Wanderer
Web
수집된 웹문서
수집 시작
URL 획득
웹 문서 다운로드
URL 추출
씨앗 URL
수집할 URL
수집된 URL
데이터마이닝 : Collective Intelligence 4
5. 검색엔진 : 웹로봇
웹로봇의 예 : 네이봇
국내 및 일본의 웹 검색 서비스인 네이버에서 이용
MySQL을 이용하여 수집된 웹 문서들을 관리
현재까지 수집된 전체 웹 문서들의 URL을 관리
과거에 수집된 웹 문서들을 지속적으로 수집함
네이봇 시스템의 구조
데이터마이닝 : Collective Intelligence 5
6. 검색엔진 : 인덱싱
동작 방법
문서를 Parsing하고, 주요 단어로 DB를 구축
Doc 1
Now is the time
for all good men
to come to the aid
of their country
Doc 2
It was a dark and
stormy night in
the country
manor. The time
was past midnight
Term Doc # Freq
a 2 1
aid 1 1
all 1 1
and 2 1
come 1 1
country 1 1
country 2 1
dark 2 1
for 1 1
good 1 1
in 2 1
is 1 1
it 2 1
manor 2 1
men 1 1
midnight 2 1
night 2 1
now 1 1
of 1 1
past 2 1
stormy 2 1
the 1 2
the 2 2
their 1 1
time 1 1
time 2 1
to 1 2
was 2 2
데이터마이닝 : Collective Intelligence 6
7. 검색엔진 : Crawler 주요 구현 함수
Web Crawler 구현을 위한 주요 기능
Seed URL을 이용하여 다운로드, Parsing 후 Indexing, 재 Crawling
searchengine.py
class crawler:
# Initialize the crawler with the name of database
def __init__(self,dbname):
def __del__(self):
def dbcommit(self):
def getentryid(self,table,field,value,createnew=True):
def addtoindex(self,url,soup):
def gettextonly(self,soup):
def separatewords(self,text):
def isindexed(self,url):
def addlinkref(self,urlFrom,urlTo,linkText):
def crawl(self,pages,depth=2):
def createindextables(self):
데이터마이닝 : Collective Intelligence 7
8. 단순 Crawler 구현
Crawler 구현 방안
Seed URL을 이용하여 다운로드, Parsing 후 Indexing, 재 Crawling
라이브러리 이용 : urllib2
Telnet을 이용한 간단 테스트
– C:> telnet mcalab.kunsan.ac.kr 80
데이터마이닝 : Collective Intelligence 8
9. 단순 Crawler 구현
urllib2를 이용한 구현
지정한 url을 다운로드하여 저장할 수 있도록 해주는 라이브러리
>> import urllib2
>> c=urllib2.urlopen('http://kiwitobes.com/wiki/Programming_language.html')
>> contents=c.read( )
>> print contents[0:50]
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Trans'
데이터마이닝 : Collective Intelligence 9
10. 단순 Crawler 구현 : Crawler 코드
이용 라이브러리
Urllib2 :
– 웹 url을 지정하여 다운로드
Beautiful Soup
– url parsing
import urllib2
from BeautifulSoup import *
from urlparse import urljoin
무시 단어 목록의 생성
# Create a list of words to ignore
ignorewords=set(['the','of','to','and','a','in','is','it'])
데이터마이닝 : Collective Intelligence 10
11. 단순 Crawler 구현 : Crawler 코드
Crawler 구현
def crawl(self,pages,depth=2):
for i in range(depth):
newpages={}
for page in pages:
try:
c=urllib2.urlopen(page)
except:
print "Could not open %s" % page
continue
try:
soup=BeautifulSoup(c.read())
self.addtoindex(page,soup)
links=soup('a')
for link in links:
if ('href' in dict(link.attrs)):
url=urljoin(page,link['href'])
if url.find("'")!=-1: continue
url=url.split('#')[0] # remove location portion
if url[0:4]=='http' and not self.isindexed(url):
newpages[url]=1
linkText=self.gettextonly(link)
self.addlinkref(page,url,linkText)
self.dbcommit()
except:
print "Could not parse page %s" % page
pages=newpages
searchengine.py
Seed urls
Download
Parsing and
Indexing
페이지내
url 추출(new page
데이터마이닝 : Collective Intelligence 11
12. 단순 Crawler 구현 : Crawler 코드
Crawler 실행
>> import searchengine
>> pagelist=['http://kiwitobes.com/wiki/Perl.html']
>> crawler=searchengine.crawler('')
>> crawler.crawl(pagelist)
Indexing http://kiwitobes.com/wiki/Perl.html
Could not open http://kiwitobes.com/wiki/Module_%28programming%29.html
Indexing http://kiwitobes.com/wiki/Open_Directory_Project.html
Indexing http://kiwitobes.com/wiki/Common_Gateway_Interface.html
데이터마이닝 : Collective Intelligence 12
13. 색인하기
색인 데이터의 저장
SQLite를 이용하여 저장
– Pysqlite
스키마 설정하기
데이터마이닝 : Collective Intelligence 13
14. 색인하기
인덱스 테이블의 생성
def createindextables(self):
self.con.execute('create table urllist(url)')
self.con.execute('create table wordlist(word)')
self.con.execute('create table wordlocation(urlid,wordid,location)')
self.con.execute('create table link(fromid integer,toid integer)')
self.con.execute('create table linkwords(wordid,linkid)')
self.con.execute('create index wordidx on wordlist(word)')
self.con.execute('create index urlidx on urllist(url)')
self.con.execute('create index wordurlidx on wordlocation(wordid)')
self.con.execute('create index urltoidx on link(toid)')
self.con.execute('create index urlfromidx on link(fromid)')
self.dbcommit( )
데이터마이닝 : Collective Intelligence 14
15. 색인하기
페이지내 단어 찾기
# Extract the text from an HTML page (no tags)
def gettextonly(self,soup):
v=soup.string
if v==Null:
c=soup.contents
resulttext=''
for t in c:
subtext=self.gettextonly(t)
resulttext+=subtext+'n'
return resulttext
else:
return v.strip()
# Seperate the words by any non-whitespace character
def separatewords(self,text):
splitter=re.compile('W*')
return [s.lower() for s in splitter.split(text) if s!='']
데이터마이닝 : Collective Intelligence 15
16. 색인하기
색인에 넣기
# Index an individual page
def addtoindex(self,url,soup):
if self.isindexed(url): return
print 'Indexing '+url
# Get the individual words
text=self.gettextonly(soup)
words=self.separatewords(text)
# Get the URL id
urlid=self.getentryid('urllist','url',url)
# Link each word to this url
for i in range(len(words)):
word=words[i]
if word in ignorewords: continue
wordid=self.getentryid('wordlist','word',word)
self.con.execute("insert into wordlocation(urlid,wordid,location) values (%d,%d,%d)" %
(urlid,wordid,i))
데이터마이닝 : Collective Intelligence 16
17. 색인하기
색인에 넣기 : getentryid
# Auxilliary function for getting an entry id and adding
# it if it's not present
def getentryid(self,table,field,value,createnew=True):
cur=self.con.execute(
"select rowid from %s where %s='%s'" % (table,field,value))
res=cur.fetchone()
if res==None:
cur=self.con.execute(
"insert into %s (%s) values ('%s')" % (table,field,value))
return cur.lastrowid
else:
return res[0]
데이터마이닝 : Collective Intelligence 17
18. 색인하기
색인에 넣기
실제 색인을 구축하는 예
>> reload(searchengine)
>> crawler=searchengine.crawler('searchindex.db')
>> pages=
.. ['http://kiwitobes.com/wiki/Categorical_list_of_programming_languages.html']
>> crawler.crawl(pages)
특정 단어를 포함한 url을 검색하는 예
>> [row for row in crawler.con.execute(
.. 'select rowid from wordlocation where wordid=1')]
[(1,), (46,), (330,), (232,), (406,), (271,), (192,),...
데이터마이닝 : Collective Intelligence 18
19. 검색하기
검색어를 포함한 URL 찾기
MyVer Computer Programming
wordlist
rowid word
101 composer
102 computer
103 programmer
104 programming
wordlocation
urlid wordid location
301 101 20
301 101 103
301 102 43
301 104 55
301 104 88
urlid url abstract
301 http://mcalab.kunsan.ac.kr MCALAB은…
302 http://cs.kunsan.ac.kr 군산대컴퓨터..
303 http://www.hani.co.kr 한겨레신문사..
304 http://www.hanrss.net
데이터마이닝 : Collective Intelligence 19
urlist
SELECT rowid
FROM wordlist
WHERE word=‘programming’
SELECT w0.urlid, w0.location, w1.location
FROM wordlocation w0, wordlocation w1
WHERE w0.urlid=w1.urlid AND
w0.wordid=102 AND w1.wordid=104
SELECT url, abstract
FROM urllist
WHERE urlid=301;
SELECT rowid
FROM wordlist
WHERE word=‘Computer’
Computer, programmming 등
동일단어가 한 url에 여러 번 출현
21. 검색하기
Getmatchrows 함수의 구현
def getmatchrows(self,q):
# Strings to build the query
fieldlist='w0.urlid'
tablelist=''
clauselist=''
wordids=[]
# Split the words by spaces
words=q.split(' ')
tablenumber=0
for word in words:
Computer Programming
SELECT rowid
FROM wordlist
WHERE word=‘programming’
SELECT rowid
FROM wordlist
WHERE word=‘Computer’
# Get the word ID
wordrow=self.con.execute(
"select rowid from wordlist where word='%s'" % word).fetchone()
if wordrow!=None:
wordid=wordrow[0]
wordids.append(wordid)
if tablenumber>0:
tablelist+=','
clauselist+=' and '
clauselist+='w%d.urlid=w%d.urlid and ' % (tablenumber-1,tablenumber)
fieldlist+=',w%d.location' % tablenumber
tablelist+='wordlocation w%d' % tablenumber
clauselist+='w%d.wordid=%d' % (tablenumber,wordid)
tablenumber+=1
wordlist
rowid word
101 composer
102 computer
103 programmer
104 programming
데이터마이닝 : Collective Intelligence 21
22. 검색하기
Getmatchrows 함수의 구현
# Create the query from the separate parts
fullquery='select %s from %s where %s' % (fieldlist,tablelist,clauselist)
print fullquery
cur=self.con.execute(fullquery)
rows=[row for row in cur]
return rows,wordids
SELECT w0.urlid, w0.location, w1.location
FROM wordlocation w0, wordlocation w1
WHERE w0.urlid=w1.urlid AND
w0.wordid=101 AND w1.wordid=104
wordlocation
urlid wordid location
301 101 20
301 101 103
301 102 43
301 104 55
301 104 88
rows [(301, 20, 55), (301, 20, 88),
(301, 103, 55), (301, 103, 88),…],
wordlist[101, 104]
데이터마이닝 : Collective Intelligence 22
23. 내용기반 랭킹
내용기반 랭킹의 점수 지표(traditional approach)
단어빈도
– 검색어 안에 있는 단어들이 문서에 출현하는 횟수
– 문서의 적합도를 결정
문서내 위치
– 다양한 단어의 위치에 대한 가정을 이용
• 한 문서의 핵심주제는 문서 도입부에 있을 가능섶이 높다
• 중요한 단어일수록 글자체가 크다
• Keyword 또는 head에 사용된 단어는 중요하다
단어거리
– 검색어 안에 여러 단어가 있을 경우 문서에서 근접해서 출현해야 한다
데이터마이닝 : Collective Intelligence 23
24. 내용기반 랭킹
내용 기반 랭킹의 구현
def getscoredlist(self,rows,wordids):
totalscores=dict([(row[0],0) for row in rows])
# 이 부분에 점수 함수를 넣음
# 현재는 score없이 db에서 리턴되는 순서 그대로 출력
weights=[]
for (weight,scores) in weights:
for url in totalscores:
totalscores[url]+=weight*scores[url]
return totalscores
def query(self,q):
rows,wordids=self.getmatchrows(q)
# 다음의 getscoredlist를 통해 url들의 리스트를 정렬
scores=self.getscoredlist(rows,wordids)
rankedscores=[(score,url) for (url,score) in scores.items()]
rankedscores.sort()
rankedscores.reverse()
for (score,urlid) in rankedscores[0:10]:
print '%ft%s' % (score,self.geturlname(urlid))
return wordids,[r[1] for r in rankedscores[0:10]]
def geturlname(self,id):
return self.con.execute(
"select url from urllist where rowid=%d" % id).fetchone()[0]
>> reload(searchengine)
>> e=searchengine.searcher('searchindex.db')
>> e.query('functional programming')
0.000000 http://kiwitobes.com/wiki/XSLT.html
0.000000 http://kiwitobes.com/wiki/XQuery.html
0.000000 http://kiwitobes.com/wiki/Unified_Modeling_Language.html
...
데이터마이닝 : Collective Intelligence 24
25. 내용기반 랭킹 : 정규화 함수
숫자 점수의 정규화
랭킹을 위해 다양한 점수화 factor를 도입
다양한 factor들간의 통합을 위해 모든 점수를 동일한 범위와 방향으로 정규화함
– 단어빈도, 문서내위치, 단어거리 등등의 factor 각각을 0..1의 값으로 변환
정규화 방법
최적 결과를 1로 가정하고 정규화
def normalizescores(self,scores,smallIsBetter=0):
vsmall=0.00001 # Avoid division by zero errors
if smallIsBetter:
minscore=min(scores.values())
return dict([(u,float(minscore)/max(vsmall,l)) for (u,l) in scores.items()])
else:
maxscore=max(scores.values())
if maxscore==0: maxscore=vsmall
return dict([(u,float(c)/maxscore) for (u,c) in scores.items()])
작은값이 더 좋은 최적결과로
할경우 smallsBetter 설정
데이터마이닝 : Collective Intelligence 25
26. 내용기반 랭킹 : 단어빈도의 점수화
단어빈도의 점수화 방법
검색어의 출현빈도가 높을 수록 높은 점수를 반환
구현 방법
def frequencyscore(self,rows):
counts=dict([(row[0],0) for row in rows])
for row in rows: counts[row[0]]+=1
return self.normalizescores(counts)
weights=[(1.0,self.frequencyscore(rows))]
urlid wordid location
301 101 20
301 101 103
301 102 43
301 104 55
301 104 88
rows [(301, 20, 55), (301, 20, 88),
(301, 103, 55), (301, 103, 88),…],
wordlist[101, 104]
counts [(301, 5),(302, 3),(503,11),…],
데이터마이닝 : Collective Intelligence 26
27. 내용기반 랭킹 : 단어빈도의 점수화
단어빈도의 점수화 방법
이용 방법
>> reload(searchengine)
>> e=searchengine.searcher('searchindex.db')
>> e.query('functional programming')
1.000000 http://kiwitobes.com/wiki/Functional_programming.html
0.262476
http://kiwitobes.com/wiki/Categorical_list_of_programming_languages.html
0.062310 http://kiwitobes.com/wiki/Programming_language.html
0.043976 http://kiwitobes.com/wiki/Lisp_programming_language.html
0.036394 http://kiwitobes.com/wiki/Programming_paradigm.html
...)
고려사항
– 정말 단어빈도가 높을 수록 점수가 높아야 하는가?
• 특정단어가 무의미하게 꽉채워진 페이지는???
• 해결방안은?
전체 페이지내의 단어갯수중에서 그 단어가 차지하는 비중을 계산
데이터마이닝 : Collective Intelligence 27
28. 내용기반 랭킹 : 문서내 위치의 점수화
문서내 위치의 점수화 방법
문서내에서 앞에 부분에 나타날수록 중요
제목 부분에 나타날수록 중요
구현방법
def locationscore(self,rows):
locations=dict([(row[0],1000000) for row in rows])
for row in rows:
loc=sum(row[1:])
if loc< locations[ row[0] ]: locations[row[0] ] = loc
return self.normalizescores(locations,smallIsBetter=1)
weights=[(1.0,self.locationscore(rows))]
rows [(301, 20, 55), (301, 20, 88),
(301, 103, 55), (301, 103, 88),…],
wordlist[101, 104]
locations[(301,75),(301,108),…)
데이터마이닝 : Collective Intelligence 28
29. 내용기반 랭킹 : 문서내 위치의 점수화
문서내 위치의 점수화 방법
이용방법
>> reload(searchengine)
>> e=searchengine.searcher('searchindex.db')
>> e.query('functional programming‘)
고려사항
– 문서내에서 단어의 폰트 크기나 색이 중요도를 결정하지는 않는가?
– Html 태그 정보를 이용하여 scoring 함으로서 중요도를 판단할 수 있지 않을까?
• <title>, <font>,<color>
데이터마이닝 : Collective Intelligence 29
30. 내용기반 랭킹 : 문서내 위치의 점수화
단어 빈도와 문서내 위치를 함께 사용
가중치를 이용하여, 최적값을 모색할 수 있음
weights=[(1.0,self.frequencyscore(rows)),
(1.5,self.locationscore(rows))]
데이터마이닝 : Collective Intelligence 30
31. 내용기반 랭킹 : 단어거리의 점수화
단어거리의 점수화 방법
검색어가 여러 개의 단어로 구성되어 있는 경우, 단어들간의 근접도에 따라 최적결과를
점수화
구현방법
def distancescore(self,rows):
# 한 단어만 있다면 모두 선택함
if len(rows[0])<=2: return dict([(row[0],1.0) for row in rows])
# 큰 값들로 딕셔너리를 초기화함
mindistance=dict([(row[0],1000000) for row in rows])
for row in rows:
dist=sum([abs(row[i]-row[i-1]) for i in range(2,len(row))])
if dist<mindistance[row[0]]: mindistance[row[0]]=dist
return self.normalizescores(mindistance,smallIsBetter=1)
weights=[(1.0,self.distancescore(rows))]
rows [(301, 20, 55), (301, 20, 88),
(301, 103, 55), (301, 103, 88),…],
wordlist[101, 104]
locations[(301,35),(301,68),…)
데이터마이닝 : Collective Intelligence 31
32. 유입링크 사용하기 : 단순 계산
유입링크(inbound link)의 의미
유입링크의 단순계산 점수화
각 페이지의 유입링크 개수를 세고, 링크 전체 개수를 페이지에 대한 지표로 사용
– 학술 논문 평가에 사용
데이터마이닝 : Collective Intelligence 32
33. 유입링크 사용하기 : 단순 계산
단순 계산 유입링크 점수화 구현
해당 url을 링크하는 url의 개수를 세서 점수화함
def inboundlinkscore(self,rows):
uniqueurls=dict([(row[0],1) for row in rows])
inboundcount=dict([(u,self.con.execute('select count(*) from link
return self.normalizescores(inboundcount)
단점 : 조작이 쉬움
where toid=%d' % u).fetchone()[0]) for u in uniqueurls])
– 점수를 높이고자 하는 페이지를 참조하는 여러 사이트를 만들어 링크되도록 함
단어빈도, 위치 등의 다른 scoring 방법과 함께 사용
inboundcount[(301,5),(302,32),…)
데이터마이닝 : Collective Intelligence 33
34. 유입링크 사용하기 : 페이지랭크 알고리즘
페이지랭크(PageRank)의 의미
PageRank 알고리즘을 이용하여 웹 페이지의 랭킹을 부여(래리 페이지)
– 웹 페이지의 중요성을 외부에서 그 웹 페이지를 가르키는 링크(역링크)를 기반으로 계산하는
알고리즘
– 즉, 역링크를 많이 가지고 있는 웹페이지 일수록 중요하다는 전제하에 페이지의 순위를 계산
페이지의 중요도
– 그 페이지에 대한 링크를 가진 다른 페이지의 중요도와 각각의 다른 페이지들이 가지고 있는 링크
수로 계산
데이터마이닝 : Collective Intelligence 34
35. 유입링크 사용하기 : 페이지랭크 알고리즘
PageRank 점수 계산 방법
Damping factor
– 특정 페이지의 href를 통해 대상 페이지에 도달할 확률
– 유입링크가 많을 수록 대상 페이지에 도달할 확률이 높음
• 즉 특정 페이지에 10개의 href가 있는데 모두 클릭한다면 100%
• 그렇지만 현실적으로 100%인 경우는 없으므로 damping factor값을 지정
– PageRank에서는 85%를 damping factor(d)로 이용
PageRank 점수 계산식
– PR(B) : B의 PageRank 점수
– L(B) : B의 링크 갯수
데이터마이닝 : Collective Intelligence 35
36. 유입링크 사용하기 : 페이지랭크 알고리즘
PageRank 점수 계산 방법
고려사항
PR(A) = 0.15 + 0.85 * ( PR(B)/links(B) + PR(C)/links(C)
+ PR(D)/links(D) )
= 0.15 + 0.85 * ( 0.5/4 + 0.7/5 + 0.2/1 )
= 0.15 + 0.85 * ( 0.125 + 0.14 + 0.2)
= 0.15 + 0.85 * 0.465
= 0.54525
– 제일 첫번째 사용될 PageRank값을 어떻게 구할까?
• 초기에 임의값을 놓고(예: 1.0) 사용한후 반복계산할수록 실제값에 가까워짐
데이터마이닝 : Collective Intelligence 36
37. 유입링크 사용하기 : 페이지랭크 알고리즘
PageRank 구현
Crawler에 추가 : 매번 수행될때마다 페이지 랭크 재게산
def calculatepagerank(self,iterations=20):
# clear out the current page rank tables
self.con.execute('drop table if exists pagerank')
self.con.execute('create table pagerank(urlid primary key,score)')
# initialize every url with a page rank of 1
for (urlid,) in self.con.execute('select rowid from urllist'):
self.con.execute('insert into pagerank(urlid,score) values (%d,1.0)' % urlid)
self.dbcommit()
for i in range(iterations):
print "Iteration %d" % (i)
for (urlid,) in self.con.execute('select rowid from urllist'):
pr=0.15
# Loop through all the pages that link to this one
for (linker,) in self.con.execute(
'select distinct fromid from link where toid=%d' % urlid):
# Get the page rank of the linker
linkingpr=self.con.execute(
'select score from pagerank where urlid=%d' % linker).fetchone()[0]
# Get the total number of links from the linker
linkingcount=self.con.execute(
'select count(*) from link where fromid=%d' % linker).fetchone()[0]
pr+=0.85*(linkingpr/linkingcount)
self.con.execute(
'update pagerank set score=%f where urlid=%d' % (pr,urlid))
self.dbcommit())
pagerank
urlid score
301
302
303
304
305
데이터마이닝 : Collective Intelligence 37
38. 유입링크 사용하기 : 페이지랭크 알고리즘
PageRank 의 사용
>> reload(searchengine)
>> crawler=searchengine.crawler('searchindex.db')
>> crawler.calculatepagerank( )
Iteration 0
Iteration 1
...
가장 높은 pagerank값을 갖는지 확인
>> cur=crawler.con.execute('select * from pagerank order by score desc')
>> for i in range(3): print cur.next( )
(438, 2.5285160000000002)
(2, 1.1614640000000001)
(543, 1.064252)
>> e.geturlname(438)
u'http://kiwitobes.com/wiki/Main_Page.html'
데이터마이닝 : Collective Intelligence 38
39. 유입링크 사용하기 : 페이지랭크 알고리즘
PageRank 점수를 랭킹에 이용하기
PageRank 점수화 함수 구현
def pagerankscore(self,rows):
pageranks=dict([(row[0],self.con.execute('select score from pagerank where
maxrank=max(pageranks.values( ))
normalizedscores=dict([(u,float(l)/maxrank) for (u,l) in pageranks.items( )])
return normalizedscores
Weight에 이용하기
urlid=%d' % row[0]).fetchone( )[0]) for row in rows])
weights=[(1.0,self.locationscore(rows)),
(1.0,self.frequencyscore(rows)),
(1.0,self.pagerankscore(rows))]
데이터마이닝 : Collective Intelligence 39
40. 유입링크 사용하기 : Linktext 활용
링크 텍스트를 이용한 점수화
Hypertext의 텍스트를 이용하여 점수화 할 수 있음
링크 텍스트를 이용한 점수화 구현
def linktextscore(self,rows,wordids):
linkscores=dict([(row[0],0) for row in rows])
for wordid in wordids:
cur=self.con.execute('select link.fromid,link.toid from linkwords,link
where wordid=%d and linkwords.linkid=link.rowid' % wordid)
for (fromid,toid) in cur:
if toid in linkscores:
pr=self.con.execute('select score from pagerank
where urlid=%d' % fromid).fetchone()[0]
linkscores[toid]+=pr
maxscore=max(linkscores.values())
normalizedscores=dict([(u,float(l)/maxscore) for (u,l) in linkscores.items()])
return normalizedscores
데이터마이닝 : Collective Intelligence 40
41. 클릭 학습 : 클릭 추적 네트워크의 설계
사용자 선택의 Feedback
검색엔진이 제공한 검색결과에 대한 선호도 정보(검색 결과중 어떤 것을 클릭했는가?)를
이용하여 검색엔진의 검색결과 ranking에 이용
Perception Network 기반의 클릭추적 네트워크
MLP(MultiLayer Perception) : 다층적 인식망
– 은닉층(hidden layer)과 쿼리층(query layer)
Query layer hidden layer output layer
데이터마이닝 : Collective Intelligence 41
42. 클릭 학습 : 클릭 추적 네트워크의 설계
Perception network의 사용 예
wordhidden
fromid toid strength
hiddenurl
fromid toid strength
데이터마이닝 : Collective Intelligence 42
43. 클릭 학습 : 클릭 추적 네트워크의 설계
Perception network을 위한 테이블 설계
wordhidden
hiddenurl
데이터마이닝 : Collective Intelligence 43
hiddennode
create_key
fromid toid strength
fromid toid strength
class searchnet:
def __init__(self,dbname):
self.con=sqlite.connect(dbname)
def __del__(self):
self.con.close()
def maketables(self):
self.con.execute('create table hiddennode(create_key)')
self.con.execute('create table wordhidden(fromid,toid,strength)')
self.con.execute('create table hiddenurl(fromid,toid,strength)')
self.con.commit()
44. 클릭 학습 : 클릭 추적 네트워크의 설계
Strength의 획득 : getstrength
def getstrength(self,fromid,toid,layer):
if layer==0: table='wordhidden'
else: table='hiddenurl'
res=self.con.execute('select strength from %s where fromid=%d and toid=%d' % (table,fromid,toid)).fetchone()
if res==None:
if layer==0: return -0.2
if layer==1: return 0
return res[0]
Strength의 설정 : setstrength
def setstrength(self,fromid,toid,layer,strength):
if layer==0: table='wordhidden'
else: table='hiddenurl'
res=self.con.execute('select rowid from %s where fromid=%d and toid=%d' % (table,fromid,toid)).fetchone()
if res==None:
self.con.execute('insert into %s (fromid,toid,strength) values (%d,%d,%f)' % (table,fromid,toid,strength))
else:
rowid=res[0]
self.con.execute('update %s set strength=%f where rowid=%d' % (table,strength,rowid))
데이터마이닝 : Collective Intelligence 44
45. 클릭 학습 : 클릭 추적 네트워크의 설계
Hiddennode 정보의 생성 : generatehiddennode
def generatehiddennode(self,wordids,urls):
if len(wordids)>3: return None
# 이 단어의 조합으로 이미 노드를 생성했었는지 확인함
sorted_words=[str(id) for id in wordids]
sorted_words.sort()
createkey='_'.join(sorted_words)
res=self.con.execute(
"select rowid from hiddennode where create_key='%s'" % createkey).fetchone()
# If not, create it
if res==None:
cur=self.con.execute(
"insert into hiddennode (create_key) values ('%s')" % createkey)
hiddenid=cur.lastrowid
# Put in some default weights
for wordid in wordids:
self.setstrength(wordid,hiddenid,0,1.0/len(wordids))
for urlid in urls:
self.setstrength(hiddenid,urlid,1,0.1)
self.con.commit()
데이터마이닝 : Collective Intelligence 45
46. 클릭 학습 : 클릭 추적 네트워크의 설계
은닉 노드의 생성 예
>> import nn
>> mynet=nn.searchnet('nn.db')
>> mynet.maketables( )
>> wWorld,wRiver,wBank =101,102,103
>> uWorldBank,uRiver,uEarth =201,202,203
>> mynet.generatehiddennode([wWorld,wBank],[uWorldBank,uRiver,uEarth])
>> for c in mynet.con.execute('select * from wordhidden'): print c
(101, 1, 0.5)
(103, 1, 0.5)
>> for c in mynet.con.execute('select * from hiddenurl'): print c
(1, 201, 0.1)
(1, 202, 0.1)
...
데이터마이닝 : Collective Intelligence 46
47. 클릭 학습 : 전방전파
전방 전파
단어를 입력으로 취해 네트워크 내에 연결들을 활성화 시키고 URL에 대한 출력 집합을
제공하는 함수
– 각 노드가 입력에 반응하는 정도를 표시하는 함수 선택
• 쌍곡선 탄젠트(hyperbolic tangent) 함수 사용
Tangent 함수
데이터마이닝 : Collective Intelligence 47
48. 클릭 학습 : 전방전파
특정 검색어에 적합한 은닉층 내 노드를 찾는 함수
getallhiddenids
def getallhiddenids(self,wordids,urlids):
l1={}
for wordid in wordids:
cur=self.con.execute(
'select toid from wordhidden where fromid=%d' % wordid)
for row in cur: l1[row[0]]=1
for urlid in urlids:
cur=self.con.execute(
'select fromid from hiddenurl where toid=%d' % urlid)
for row in cur: l1[row[0]]=1
return l1.keys()
데이터마이닝 : Collective Intelligence 48
49. 클릭 학습 : 전방전파
데이터베이스에 저장된 모든 현재 가중치 네트워크 생성 함수
setupnetwork
def setupnetwork(self,wordids,urlids):
# value lists
self.wordids=wordids
self.hiddenids=self.getallhiddenids(wordids,urlids)
self.urlids=urlids
# node outputs
self.ai = [1.0]*len(self.wordids)
self.ah = [1.0]*len(self.hiddenids)
self.ao = [1.0]*len(self.urlids)
# create weights matrix
self.wi = [[self.getstrength(wordid,hiddenid,0)
for hiddenid in self.hiddenids]
for wordid in self.wordids]
self.wo = [[self.getstrength(hiddenid,urlid,1)
for urlid in self.urlids]
for hiddenid in self.hiddenids]
데이터마이닝 : Collective Intelligence 49
50. 클릭 학습 : 전방전파
전방전파 알고리즘
은닉층에 있는 모든 노드들마다 루프를 돌면서 입력층의 모든 출력들과 링크들의 연결강도를
곱한후 더하며 동작
def feedforward(self):
# 검색 단어가 유일한 입력
for i in range(len(self.wordids)):
self.ai[i] = 1.0
# 은닉노드 활성화
for j in range(len(self.hiddenids)):
sum = 0.0
for i in range(len(self.wordids)):
sum = sum + self.ai[i] * self.wi[i][j]
self.ah[j] = tanh(sum)
# output activations
for k in range(len(self.urlids)):
sum = 0.0
for j in range(len(self.hiddenids)):
sum = sum + self.ah[j] * self.wo[j][k]
self.ao[k] = tanh(sum)
return self.ao[:]
데이터마이닝 : Collective Intelligence 50
52. 클릭 학습 : 역전파 학습(backpropagation)
Backpropagation 이란
신경망을 훈련시키기 위해 사용하는 기술
네트워크에서 역방향으로 움직이면서 가중치를 변경
def backPropagate(self, targets, N=0.5):
# 출력 오류를 계산함
output_deltas = [0.0] * len(self.urlids)
for k in range(len(self.urlids)):
error = targets[k]-self.ao[k]
output_deltas[k] = dtanh(self.ao[k]) * error
# hidden layer의 오류를 계산함
hidden_deltas = [0.0] * len(self.hiddenids)
for j in range(len(self.hiddenids)):
error = 0.0
for k in range(len(self.urlids)):
error = error + output_deltas[k]*self.wo[j][k]
hidden_deltas[j] = dtanh(self.ah[j]) * error
# update output weights
for j in range(len(self.hiddenids)):
for k in range(len(self.urlids)):
change = output_deltas[k]*self.ah[j]
self.wo[j][k] = self.wo[j][k] + N*change
# update input weights
for i in range(len(self.wordids)):
for j in range(len(self.hiddenids)):
change = hidden_deltas[j]*self.ai[i]
self.wi[i][j] = self.wi[i][j] + N*change
노드의 현재 출력과 출력되어야 하는 값의 차이를 계산
Dthanh함수를 사용해서 해당 노드의 전체 입력값을
어느 정도 변경해야하는 지 결정
입력 링크의 현재 강도와 합습 비율에 비례해서
모든 입력 연결의 강도를 변경
데이터마이닝 : Collective Intelligence 52
53. 클릭 학습 : 역전파 학습(backpropagation)
Feedforward를 실행한 후 역전파를 실행하는 메소드
Trainquery
def trainquery(self,wordids,urlids,selectedurl):
# generate a hidden node if necessary
self.generatehiddennode(wordids,urlids)
self.setupnetwork(wordids,urlids)
self.feedforward()
targets=[0.0]*len(urlids)
targets[urlids.index(selectedurl)]=1.0
error = self.backPropagate(targets)
self.updatedatabase()
updatedatabase
def updatedatabase(self):
# set them to database values
for i in range(len(self.wordids)):
for j in range(len(self.hiddenids)):
self.setstrength(self.wordids[i],self. hiddenids[j],0,self.wi[i][j])
for j in range(len(self.hiddenids)):
for k in range(len(self.urlids)):
self.setstrength(self.hiddenids[j],self.urlids[k],1,self.wo[j][k])
self.con.commit()
데이터마이닝 : Collective Intelligence 53
55. 클릭 학습 : 학습 테스트
학습 테스트
>> allurls=[uWorldBank,uRiver,uEarth]
>> for i in range(30):
... mynet.trainquery([wWorld,wBank],allurls,uWorldBank)
... mynet.trainquery([wRiver,wBank],allurls,uRiver)
... mynet.trainquery([wWorld],allurls,uEarth)
...
>> mynet.getresult([wWorld,wBank],allurls)
[0.861, 0.011, 0.016]
>> mynet.getresult([wRiver,wBank],allurls)
[-0.030, 0.883, 0.006]
>> mynet.getresult([wBank],allurls)
[0.865, 0.001, -0.85]
데이터마이닝 : Collective Intelligence 55
56. 클릭 학습 : 검색엔진에 연결하기
점수화 구현
nnscore
def nnscore(self,rows,wordids):
# Get unique URL IDs as an ordered list
urlids=[urlid for urlid in dict([(row[0],1) for row in rows])]
nnres=mynet.getresult(wordids,urlids)
scores=dict([(urlids[i],nnres[i]) for i in range(len(urlids))])
return self.normalizescores(scores)
데이터마이닝 : Collective Intelligence 56