ノート/テキストマイニング

訪問者数 1004      最終更新 2013-06-22 (土) 09:26:02

Contents

ツイートをMeCabで分解して、targetの単語を含むツイートを数える --- 2012/10/21

やることは

プログラムは次のようになった。2つ間違いがある。

1つは、ヒットしたツイート数を数える代わりに、ヒットした回数を数えてしまっている。だから、もし1つのツイート中に複数のヒットがあれば、その数を数えてしまう。

もう1つは、パフォーマンス上のものだが、単にtarget単語を含むツイートを数えるだけなら、SQLでLIKEとCOUNTを使うか、またはツイート全体をPythonの正規表現を使った方が、ここでやっているようなMeCabでの形態素解析をするより、はるかに早いはずである。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# dbtowordfreq.py <word>
# 1) DBから読む
# 2) MeCabで単語に分割する
# 3) targetの語に一致する語を含むツイート数を数え、全ツイート数との比を求める
# 4) グラフに表示する

import sys
import codecs
import time
import datetime
import matplotlib
matplotlib.use('Agg')   # グラフをpngで出力するため
import matplotlib.pyplot as plt
from pylab import *
import MeCab
import MySQLdb
import string
from dbinit import dbinit   # 自前のdbinitを呼出すため

argvs = sys.argv    # コマンドラインパラメタとしてtargetを与える
argc = len(argvs)
if (argc != 2):
  print 'Usage: python %s targetword' % argvs[0]
  quit()
 
target = argvs[1]
print target
 
while 1:
  try:
    con = dbinit()
    d = datetime.datetime.today()
    x = []
    xt = []
    y = []
    fig = plt.figure()
    mt = MeCab.Tagger()
    #for  i in range(-2,1):
    for  i in range(-48,1):    # 過去48時間にさかのぼってツイート数を計算
      t =  (d + datetime.timedelta(hours=i)).strftime("%y%m%d%H")  # テーブル名に当る文字列 yymmddHH を現在時刻から作成
      tablename = "tw" +  t

      # DB内に、上記tで指定したテーブルが未だ出来ていないことがあるのでチェックする(時刻が変わった直後)
      s = "SHOW TABLES FROM twitter like '" + tablename + "'"  # SHOW TABLEからテーブル名を検索
      cur = con.cursor()
      cur.execute(s.encode('utf_8'))
      cnt = cur.rowcount
      if (cnt==0):
        cur.close()
        print "No table"   # テーブルがなかったら何もしないことにした
        break
      cur.close()
      # テーブルの有無チェック終り

      c = 0
      count = 0
      s = "SELECT text FROM " + tablename
      cur = con.cursor()
      cur.execute(s)

      r = cur.fetchone()
      while (r != None):
        m = mt.parseToNode(r[0].encode('utf_8'))    # MeCabで単語に分解
        while m:
          go = m.surface
          if (target == go):
            count = count + 1  # 一致する語数をカウントする
          m = m.next
        # print "EOS"

        r = cur.fetchone()
        c = c+1    # cは総ツイート数をカウントする

      cur.close()
      if (c!=0):   # cが0のことがあるためチェック
        ratio = float(count)/float(c) * 10000.0
      else:
        ratio = 0.0
      x.append(i)              # xの側はiのリストを作る。この順に表示する
      #nichiji = t[4:6]+u'日'+t[6:]+u'時'
      nichiji = t[6:]+u'時'    # グラフx軸の刻みに表示するための時刻部分
      xt.append(nichiji)       # xt (xtick) のリストを作る
      y.append(ratio)          # yの側はratioのリストを作る
      print u"時刻", nichiji, u"サンプル数", c, u"カウント数", count, u"比率", ratio

    con.close()

    # ここからグラフ表示処理 matplotlibを使う
    fig.clf()                  # figureをクリア
    sb = subplot(111)          # subplotを作る(後でtickを書き直すときに必要)
    plt.plot(x,y,'bo-')        # グラフを描く。b=青、o=丸を描く。-=直線
    title(u'語「' + unicode(target) + u'」を含むツイート数(1時間当り)', fontname="VL Gothic", fontsize=20)  # 漢字なのでフォント指定必要
    #xlabel(u'日/時', fontname="VL Gothic")
    xlabel(u'時刻', fontname="VL Gothic")
    for tick in sb.xaxis.get_major_ticks():   # すべてのx tickの向きを270度にする
      #tick.label.set_rotation('vertical')
      tick.label.set_rotation(270)

    xticks(x, xt)   # xの値に対してxtのtick値を描く
    ylabel(u'ツイート比', fontname="VL Gothic")
    ylim(ymin=0)    # y軸の起点を0からにする(そうしないと適当な値から描く)
    plt.savefig('/var/www/html/tw/twplot2.png')  # 図を絵としてファイル出力
    plt.close(fig)
    #print y
    time.sleep(30)      # 30秒おきに繰り返す

  except KeyboardInterrupt:
    print "終了Ended by Ctrl-C"
    quit()

これで、画像ファイルtwplot2.pngが作られるので、それを見ればよい。このプログラムはこのファイルに書ける権限を持つ必要がある。

画像ファイルを見るためのHTMLは、この程度でよい

<html>
<head>
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="refresh" content="30">
</head>
<body>
<img src="twplot.png">
</body>
</html>

ツイートをMeCabで分解して、targetの単語を含むツイートを数える (改良版) --- 2013/06/21

グラフ図画をファイルに書き出すとCGIにしたときにそのファイルの管理(アクセス権も含めて)が面倒なので、直接描画させる(=pngファイルを作らない)。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import MySQLdb
import codecs
import os
import sys
import cgi
import cgitb; cgitb.enable()
import time
import datetime
import tempfile
os.environ[ 'MPLCONFIGDIR' ] = tempfile.mkdtemp()  ## This is necessary before importing matplotlib
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from pylab import *          ## Needs this instead of "import pylab" for some reason

## Note that "sys.stdout = codecs.getwriter('utf_8')(sys.stdout)" should be omitted.
##    Otherwise, output image data will be transcoded.

# Change default settings
rcParams['font.family'] = 'VL Gothic'    # This allows Kanji without MojiBake
rcParams['figure.figsize'] = (9,7)       # Size of figure to 9in x 7in

#Path input data from the html FORM page
form = cgi.FieldStorage()

titleword = unicode(form["keyword"].value)
sstring = u'%' + unicode(titleword) + u'%'

try:
  while 1:                   # This infinite loop may be omitted.
    d = datetime.datetime.today()
    con = MySQLdb.connect(db="****", host="localhost", port=3306,
                user="****", passwd="****")
    x = []
    xt = []
    y = []
    #fig = plt.figure(figsize=(12,7))
    for  i in range(-72,1):
    #for  i in range(-120,1):
       t =  (d + datetime.timedelta(hours=i)).strftime("%y%m%d%H")
       tablename = "tw" +  t

       s = "SHOW TABLES FROM twitter like '" + tablename + "'"
       cur = con.cursor()
       cur.execute(s.encode('utf_8'))
       cnt = cur.rowcount
       if (cnt==0):
         cur.close()
         #print "No table"
         break

       cur.close()
       s = ("SELECT COUNT(*) FROM " + tablename + " WHERE text LIKE '" + sstring + "'").encode('utf_8')

       #print s
       cur = con.cursor()
       cur.execute(s)
       r = cur.fetchone()
       cur.close()
       x.append(i)
       nichi = t[4:6]
       ji = t[6:]
       if ((int(ji)%3)==0):
         xt.append(nichi+'/'+ji)
       else:
         xt.append('')
       y.append(r[0])

    con.close()

    sb = subplot(111)
    plt.plot(x,y,'bo-')
    title(u'Number of Observed Kanji Tweets per Hour "'+titleword.encode('utf_8')+u'"', fontsize=20)
    xlabel('Day/Hour')
    ylabel('Number of Tweets')
    for tick in sb.xaxis.get_major_ticks():
       tick.label.set_rotation(270)
    xticks(x, xt)

    # save the plot as a png and output directly to webserver
    print "Content-Type: image/png\n"
    plt.savefig( sys.stdout, format='png' )

    time.sleep(60)

except KeyboardInterrupt:
  #print "終了Ended by Ctrl-C"
  quit()

このファイル名を cgi-bin/tw/twplot3.py であるとすると、それを起動する<FORM>を含むHTMLファイルは、

<html>
<body>
  <form method="POST" action="../cgi-bin/tw/twplot3.py">
    <input type="text" name="keyword">
    <input type="submit" value="送信">
  </form>
</body>
</html>

のように書くことになる。ここのkeywordから検索キーワードをCGIに渡す。

漢字を表示するためには(デフォルトのフォントは漢字を含まないので)フォントを変更する必要がある。 毎回書くたびにフォントを指定する方法だと

    title(u'Number of Observed Kanji Tweets per Hour "'+titleword.encode('utf_8')+u'"', fontsize=20, fontname='VL Gothic')
    xlabel('Day/Hour', fontname='VL Gothic')
    ylabel('Number of Tweets', fontname='VL Gothic')

のように書くが、面倒に感じる。システム全体に対するフォントの変更はrcファイルでも可能(ここ参照)だが、他のケースで困るといけないので、このプログラムの中だけの変更にしたい(が書くたびに指定するのは嫌だ)。そういう時には、

 rcParams['font.family'] = 'VL Gothic'    # This allows Kanji without MojiBake

として設定できる。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2013-06-22 (土) 09:26:02 (1553d)