Blogから単語の数の情報が入っている行列を作り出す

Ruby側の正規表現で記号っぽい文字を取り除くことにした。あんま変わってない。あとはhtmlっぽいところがまだ入ってくるので、その辺は自分でフィルタをかけないとだめだな。

extract_meisi_from_blog <- function(url){
  ruby <- paste("
require %q[rubygems]
require %q[open-uri]
require %q[hpricot]
require %q[MeCab]
require %q[kconv]

url = %q[",url,"]

description = %q[]

begin
  doc = Hpricot(open(url).read)
rescue => ex
  exit
end

(doc/:item).each {|item|
  description = description + (item/:description).inner_text
}

begin 
  c = MeCab::Tagger.new(%q[-Ochasen]) 
  n = c.parseToNode(description) 

  list = Array.new
  while n do
    f = n.feature.split(/,/)
    if /名詞/ =~ f[0]
      if /([0-9A-Za-z_ぁ-んァ-ヴ一-]){2,}/ =~ n.surface
        list.push(n.surface)
      end
    end
    n = n.next
  end 
  list.each{|x| puts x}
rescue
  exit
end
",sep="")
  return(system(paste("echo '",ruby,"'"," | /opt/local/bin/ruby ",sep=""),intern=TRUE))
}

これをとりあえずこんな感じでつめこめばいいかな。

> head(hoge)
   words  V2 V3  V4
1  class 514 21  56
2    cgi 481  1   0
3   span 451 18  26
4  theta 336  0   0
5 hatena 304 10 118
6   http 293 69 130
> summary(hoge)
    words                 V2                V3                V4         
 Length:2895        Min.   :  0.000   Min.   :  0.000   Min.   :  0.000  
 Class :AsIs        1st Qu.:  0.000   1st Qu.:  0.000   1st Qu.:  0.000  
 Mode  :character   Median :  0.000   Median :  0.000   Median :  0.000  
                    Mean   :  3.344   Mean   :  1.215   Mean   :  1.759  
                    3rd Qu.:  1.000   3rd Qu.:  1.000   3rd Qu.:  1.000  
                    Max.   :514.000   Max.   :519.000   Max.   :224.000  

どんどんdata.frameにbindしていくつもりだったんだけど、挫折した。結局、listの要素にベクトルを持たせるという感じになっている。

> str(a)
List of 3
 $ : int [, 1:1041] 514 481 451 336 304 293 290 290 248 245 ...
  ..- attr(*, "dimnames")=List of 1
  .. ..$ : chr [1:1041] "class" "cgi" "span" "theta" ...
 $ : int [, 1:1009] 519 69 46 44 39 32 30 28 26 25 ...
  ..- attr(*, "dimnames")=List of 1
  .. ..$ : chr [1:1009] "br" "http" "com" "href" ...
 $ : int [, 1:1388] 224 130 126 124 118 117 109 98 80 79 ...
  ..- attr(*, "dimnames")=List of 1
  .. ..$ : chr [1:1388] "li" "http" "ul" "br" ...
a <- list()

for(url in c("http://d.hatena.ne.jp/syou6162/rss2","http://blog.isocchi.com/rss.xml","http://d.hatena.ne.jp/Hash/rss2")){
  cat(url,fill=T)
  word <- table(extract_meisi_from_blog(url))
  b <- list(word[order(word,decreasing=TRUE)])
  a <- append(a,b)  
}

hoge <- data.frame(words=I(unique(unlist(mapply(names,a)))))

for(i in seq(length(a))){
  hoge[,i+1] <- as.numeric(mapply(function(x){ifelse(!is.na(a[[i]][x]),a[[i]][x],0)},hoge$words))
}

たぶん後のほうでは、行列に近い形のほうが扱いやすいような気がするので、整形しておく。

#keywordをrow.namesにして、データフレームから出しておく
row.names(hoge) <- hoge$words
hoge$words <- NULL

#colのnameのほうはblogのurlにしておく
names(hoge) <- as.character(get_blogs_from_opml()$V2)[1:20]

すると、as.matrixをすぐにでもできる形になっている。

> head(hoge[,1:3])
       http://totodaisuke.weblogs.jp/blog/atom.xml
の                                               0
Perl                                             0
http                                             0
Apache                                           0
jp                                               00
       http://feeds.feedburner.jp/shebang http://svslab.jp/0x0a/index.rdf
の                                      9                               7
Perl                                    5                               0
http                                    5                               0
Apache                                  4                               0
jp                                      4                               04                               0

feedのtypeがatomになっているやつは行列に入っている数字が全部0とかいうことになっているので*1、そこははぶいたりする。applyかわいい。

hoge <- hoge[,as.vector(apply(hoge,2,function(x){!all(x == 0)}))]

*1:スクレイピングのところをrss形式でしか処理していないから