<?xml version="1.0" encoding="UTF-8" ?>
<entry
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
	xml:lang="ja-JP"
>
	<title>MySQLでTF-IDFの計算、あと2つのベクトルの内積の計算</title>
	<id>tag:txqz.net,2006-12-19:blog/2006/12/19/2347</id>
	<link rel="self" href="http://txqz.net/blog/2006/12/19/2347.atom"/>
	<link rel="alternate" type="application/rss+xml" href="http://txqz.net/blog/2006/12/19/2347.rdf"/>
	<link rel="alternate" type="application/xhtml+xml" href="http://txqz.net/blog/2006/12/19/2347.xhtml"/>
	<link rel="alternate" type="text/html" href="http://txqz.net/blog/2006/12/19/2347.html"/>
	<link rel="contents" href="http://txqz.net/blog/2006/12/19/.atom" title="2006年12月19日"/>
	<link rel="first" href="http://txqz.net/blog/2001/08/04/0001.atom" title="地球空冷化"/>
	<link rel="prev" href="http://txqz.net/blog/2006/12/18/0018.atom" title="回文文化"/>
	<link rel="next" href="http://txqz.net/blog/2006/12/20/2349.atom" title="ミアたんが好きです。"/>
	<link rel="last" href="http://txqz.net/blog/2008/12/19/2152.atom" title="浜松市街地を通り抜けて、ムーンライトながら～の思い出"/>
	<author>
		<name>陽坂智佐</name>
		<email>spambasket@txqz.net</email>
	</author>
	<content type="xhtml">
		<div xmlns="http://www.w3.org/1999/xhtml">
<p>本文を形態素分解し、必要な品詞をtfテーブルとdfテーブルに入れる。分析対象となる文書群すべてについてこの処理を行い、各形態素のTF-IDF値を求めて文書をベクトル化する。他の文書ベクトルと内積を比較し、小さい順に「似ている記事」を求めたい (クラスタリングとかは別途)。</p>
<p>HarmanによるTF値の正規化とSparok JonesによるDF値の正規化をする場合のTF-IDF値の計算式は以下のようになる (<a href="http://www.r.dl.itc.u-tokyo.ac.jp/~nakagawa/infoDB/ir-vector.pdf">参考文献</a>):</p>
<pre><code class="math">tfidf(i,j) = log2(freq(i,j) + 1) / log2(NoT) * (log2(N / Dfreq(i)) + 1)</code></pre>
<h2>HarmanによるTFの正規化</h2>
<pre><code class="math">tf(i,j) = log2(freq(i,j) + 1) / log2(NoT)</code></pre>
<dl>
<dt>tf(i,j)</dt><dd>文書jにおける単語iのTF値</dd>
<dt>freq(i,j)</dt><dd>文書jにおける単語iの登場回数</dd>
<dt>NoT</dt><dd>文書j中のタームの種類数(num of terms)</dd>
</dl>
<h2>Sparck JonesによるDFの正規化</h2>
<pre><code class="math">idf(i) = log2(N / Dfreq(i)) + 1</code></pre>
<dl>
<dt>idf(i)</dt><dd>単語iのDF値</dd>
<dt>N</dt><dd>文書集合中の文書総数</dd>
<dt>Dfreq(i)</dt><dd>単語iが登場する文書数</dd>
</dl>
<h2>MySQL での表現</h2>
<dl>
<dt>TF値の分子</dt><dd><pre><code class="sql">SELECT log2(times + 1) FROM tf WHERE item='j' AND tag='i';</code></pre></dd>
<dt>TF値の分母</dt><dd><pre><code class="sql">SELECT log2(count(tag)) FROM tf WHERE item='j' GROUP BY item;</code></pre></dd>
<dt>IDF値のlogの分子</dt><dd><pre><code class="sql">SELECT count(id) FROM article;</code></pre></dd>
<dt>IDF値のlogの分母</dt><dd><pre><code class="sq;">SELECT times FROM df WHERE tag = 'i';</code></pre></dd>
</dl>
<p>全部くっつけると:</p>
<pre><code class="sql">SELECT item, tag, log2(tf.times + 1) / log2(total) * (log2(n / df.times) + 1) AS tfidf
  FROM tf
    LEFT JOIN df USING(tag)
    LEFT JOIN (SELECT item, count(tag) total FROM tf GROUP BY item) AS a USING(item)
    CROSS JOIN (SELECT count(id) AS n FROM items) AS b
  WHERE item="<var>j</var>";</code></pre>
<p>実際はユーザ変数を使った方がSQLが短くなっていいと思う。</p>
<pre><code class="sql">SELECT @total := count(tag) FROM tf WHERE item = "<var>j</var>";
SELECT @n := count(id) FROM items;
SELECT item, tag, log2(tf.times + 1) / log2(@total) * (log2(@n / df.times) + 1) AS tfidf
  FROM tf LEFT JOIN df USING(tag)
  WHERE item="<var>j</var>";</code></pre>
<p>これで記事の各形態素のTFIDF値が求められたので、tfidfテーブルに保管しておく。</p>
<h2>内積を求めて近い記事を出す</h2>
<p>とりあえず各記事の上位100単語くらいを使うことにする。</p>
<pre><code class="sql">INSERT INTO tfidf
  SELECT item, tag, log2(tf.times + 1) / log2(@total) * (log2(@n / df.times) + 1) AS tfidf
    FROM tf LEFT JOIN df USING(tag)
    WHERE item="<var>j</var>"
    ORDER BY tfidf DESC
    LIMIT 100;</code></pre>
<p>ある文書wがn次元のベクトルで表せる (w = {w<sub>1</sub> w<sub>2</sub> ... w<sub>n</sub>})とき、文書wとxの内積は</p>
<pre><code class="math">Σ(w<sub>i</sub> * v<sub>i</sub>) / √(Σ(w<sub>i</sub><sup>2</sup>) * Σ(v<sub>i</sub><sup>2</sup>))</code></pre>
<p>MySQLで書くと</p>
<pre><code class="sql">CREATE TEMPORARY TABLE inp
  SELECT self.tag, self.tfidf self, target.tfidf target
    FROM tfidf self
      LEFT JOIN (SELECT tag,tfidf FROM tfidf WHERE item='<var>v</var>') target USING(tag)
    WHERE self.item = '<var>w</var>';
SELECT sum(self * target) / sqrt(sum(pow(self,2))*sum(pow(target,2))) inp FROM inp</code></pre>
<h2>実際にやってみる</h2>
<p>実際にニュー速各板のスレでやってみた。だいたい同じニュースの続きのスレだと0.6以上の高い値に、似たようなネタの異なるニュースの場合は0.3～0.4くらいになった。以下はそれらの例。カッコ内が内積</p>
<h3>高い値 …… 同じニュースの次スレ、前スレ</h3>
<dl>
<dt>【経済】 「格差是正のため、正社員の待遇を非正規社員水準に合わせる」…経済財政諮問会議・八代氏★５</dt>
<dd><ul>
<li>【経済】 「格差是正のため、正社員の待遇を非正規社員水準に合わせる」…経済財政諮問会議・八代氏★４ (0.76865722990833)</li>
<li>【経済】 「格差是正のため、正社員の待遇を非正規社員水準に合わせる」…経済財政諮問会議・八代氏★３ (0.72848890331971)</li>
<li>【経済】「格差是正のため正社員待遇を非正規社員水準へ」…経済財政諮問会議メンバー・八代尚宏氏★２ (0.61619675121174)</li>
<li>【経済】「格差是正のため正社員待遇を非正規社員水準へ」…経済財政諮問会議メンバー・八代尚宏氏 (0.63664490692797)</li>
</ul></dd>
<dt>【芸能】森本レオが石原真理子の処女を奪ったことを認める「それでもやっぱりマリコがんばれ」</dt>
<dd><ul>
<li>【芸能】石原真理子「17歳で森本レオに処女奪われた」…週刊誌に暴露、「宣伝か」の声も★２ (0.82246383998552)</li>
<li>【芸能】石原真理子「17歳で森本レオに処女奪われた」…週刊誌に暴露、「宣伝か」の声も[12/18] (0.79417204039799)</li>
</ul></dd>
<dt>◆自治議論★64◆</dt>
<dd><ul>
<li>愛の説教部屋166(地獄キャンペーン実施中)（　ﾟдﾟ) (0.67651278868912)</li>
<li>◆自治議論★63◆ (0.81182145799799)</li>
<li>◆自治議論★62◆ (0.79929338782244)</li>
</ul></dd>
</dl>
<h3>中くらいの値 …… 似たようなネタだが異なるニュースのスレ</h3>
<dl>
<dt>【MLB】多田野、アスレチックスと再契約 春季キャンプでメジャー復帰目指す★３</dt>
<dd><ul>
<li>【社会】 ＮＨＫ職員（男）、電車で大学生（１８０cm・１２０kgの男子）に痴漢→逮捕…東京★３ (0.4629403483907)</li>
<li>【社会】 ＮＨＫ職員（男）、電車で大学生（男子）に痴漢→逮捕…東京★２ (0.41509734340642)</li>
</ul></dd>
<dt>【大阪】コリアNGOセンター事務局長「公立校で民族教育は不要との意見が出かねない…外国籍の子供に愛国心強調しないで」［12/18］</dt>
<dd><ul>
<li>【論説】 「"日教組が、教育荒廃の元凶"というのは言いがかりだ」…東京新聞★２ (0.35593573724151)</li>
<li>【日韓】 ［特派員コラム］韓国は日本を追い越すことができる?潜在力も意欲も韓国が上[12/18] (0.3069814685099)</li>
<li>【論説】 「愛国心、"格差"はぐらかす為か？ 学生らは愛国心強要に"日本社会の悪化"を感じている」…毎日新聞★３ (0.39403589906126)</li>
</ul></dd>
<dt>【フィギュアスケート】高橋・安藤・浅田・村主ら日本勢に謎の症状･･･体調不良者が続出★３</dt>
<dd><ul>
<li>【北海道】カキ「風評被害」に悲鳴、取扱額４０％減　ノロウイルス食中毒、今季の感染例ゼロなのに★２ (0.41831300355656)</li>
</ul></dd>
</dl>
<p>今回やってみて、同じニュースのスレッドは★１だろうが★８だろうが同じようなことを延々と話しているのではないかと感じた。何スレも立つような息の長いニュースについて、スレッドごとの単語の登場の仕方とか共起の仕方を見ていくと、ニュー速民のニュースへの態度を表せたりするかも。面白いのはフィギュアスケート選手の体調不良の記事とカキの風評被害の記事が関連付けられたこと。フィギュアスケートの記事中に「カキ」への言及がなくても、ニュー速民による噂話の可視化によって、実は関係あるかもしれない2つの記事が結びついた。なんか集合知かも～。</p>
<ins class="ps" datetime="2007-06-02T19:43:05+09:00" id="PS20070602194305">
<p>このとき使ったのと似たような手法を<a href="http://sangi.in/kouho">候補者ブログクローラ</a>でも使っています。</p>
</ins>
		</div>
	</content>
	<category term="MySQL"/>
	<category term="SQL"/>
	<category term="TF-IDF"/>
	<category term="ベクトル空間"/>
	<category term="内積"/>
	<category term="自然言語処理"/>
	<trackback:ping>http://txqz.net/blog/2006/12/19/2347/tb</trackback:ping>
	<published>2007-06-02T19:43:05+09:00</published>
	<updated>2007-12-04T18:55:11+09:00</updated>
	<rights>Attribution-Noncommercial-Share Alike 3.0 Unported</rights>
</entry>