Yahoo! Japan Developer Network : 日本語形態素解析サービスの利用
/* * Yahoo! Japan ディベロッパーネットワーク: テキスト解析:形態素解析サービスの利用 * http://developer.yahoo.co.jp/webapi/jlp/ma/v1/parse.html * 2015.11.18 */ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.io.InputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import javax.xml.xpath.*; import java.util.ArrayList; public class YahooMorph { private String appid; private final String path = "http://jlp.yahooapis.jp/MAService/V1/parse?"; // 形態素 (morpheme)クラス public class Morpheme { private String surface; private String reading; private String pos; private String baseform; public Morpheme(String surface, String reading, String pos, String baseform){ this.surface = surface; this.reading = reading; this.pos = pos; this.baseform = baseform; } // getter public String getSurface(){ return surface; } public String getReading(){ return reading; } public String getPos(){ return pos; } public String getBaseform(){ return baseform; } } public YahooMorph(String appid){ this.appid = appid; } public ArrayList<Morpheme> analyse(String text){ // 形態素を格納するリスト ArrayList<Morpheme> morph_list = new ArrayList<Morpheme>(); try{ // リクエスト URL およびその引数については下記を参照 // http://developer.yahoo.co.jp/webapi/jlp/ma/v1/parse.html // (注)日本語文字列は予め URL encoding しなければならない。 URL url = new URL(path + "appid=" + appid + "&results=ma&response=surface,reading,pos,baseform&sentence=" + URLEncoder.encode(text, "utf-8")); // Yahoo! Developer Web service とのコネクションを張る HttpURLConnection http = (HttpURLConnection)url.openConnection(); http.setRequestMethod("GET"); // GET メソッドによるアクセス http.connect(); // サーバから返される XML を処理するための document builder の設定 InputStream input = url.openStream(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(input); // XML の解析(parsing)に XPath を用いる。 // XPath の解説は下記サイトが詳しい。 // http://www.techscore.com/tech/XML/XPath/index.html XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); // 表層形 (surface), 読み (reading), 品詞 (pos),基本形 (baseform)の取り出し NodeList surfaces = (NodeList)xpath.evaluate("//ma_result/word_list/word/surface/text()", doc, XPathConstants.NODESET); NodeList readings = (NodeList)xpath.evaluate("//ma_result/word_list/word/reading/text()", doc, XPathConstants.NODESET); NodeList poses = (NodeList)xpath.evaluate("//ma_result/word_list/word/pos/text()", doc, XPathConstants.NODESET); NodeList baseforms = (NodeList)xpath.evaluate("//ma_result/word_list/word/baseform/text()", doc, XPathConstants.NODESET); // デバッグ用の出力 /* for(int i=0; i < surfaces.getLength(); i++){ System.out.println(surfaces.item(i).getNodeValue()); } for(int i=0; i < readings.getLength(); i++){ System.out.println(readings.item(i).getNodeValue()); } for(int i=0; i < poses.getLength(); i++){ System.out.println(poses.item(i).getNodeValue()); } for(int i=0; i < baseforms.getLength(); i++){ System.out.println(baseforms.item(i).getNodeValue()); } */ // 各形態素の表層形 (surface), 読み (reading), 品詞 (pos),基本形 (baseform)を // 形態素解析リストへ格納 for(int i=0; i < surfaces.getLength(); i++){ morph_list.add(new Morpheme(surfaces.item(i).getNodeValue(), readings.item(i).getNodeValue(), poses.item(i).getNodeValue(), baseforms.item(i).getNodeValue())); } http.disconnect(); // コネクションの切断 } catch(Exception e){ System.out.println(e); System.exit(1); } return morph_list; } public static void main(String[] args) { // Application ID の取得方法は下記を参照: // http://developer.yahoo.co.jp/start/ String appid = "xxxx"; YahooMorph yahooMorph = new YahooMorph(appid); // 形態素解析(その1) String text = "明日,晴れることを願っている。"; ArrayList<Morpheme> result = yahooMorph.analyse(text); System.out.println("=== Example 1 ==="); for(int i=0; i < result.size(); i++){ Morpheme m = result.get(i); System.out.println(m.getSurface() + "\t" + m.getReading() + "\t" + m.getPos() + "\t" + m.getBaseform()); } // 形態素解析(その2) text = "JavaもC言語もどちらも大切でしょう。"; result = yahooMorph.analyse(text); System.out.println("=== Example 2==="); for(int i=0; i < result.size(); i++){ Morpheme m = result.get(i); System.out.println(m.getSurface() + "\t" + m.getReading() + "\t" + m.getPos() + "\t" + m.getBaseform()); } } }
EMアルゴリズムによるGMMパラメータの推定
トピックモデルでは EM アルゴリズムを用いるのが一般的なのに,EM の理屈を理解できていない。
そこで,GMM (Gaussian Mixture Model) のパラメータ推定を対象とし,
Simon J.D. Prince, Computer vision: models, learning and inference (2012)
で勉強しつつの,
http://nbviewer.ipython.org/github/tritemio/notebooks/blob/master/Mixture_Model_Fitting.ipynb
に掲載されていたコードを打ち込んでみた。
#coding: utf-8 ''' 下記サイトに掲載されていたコード http://nbviewer.ipython.org/github/tritemio/notebooks/blob/master/Mixture_Model_Fitting.ipynb ''' import numpy as np from numpy import random from scipy.optimize import minimize, show_options import matplotlib.mlab as mlab np.random.seed(1) # 2つの正規分布を重み (0.3, 0.7) で混合する N=1000 a=0.3 s1 = random.normal(0, 0.08, size=N*a) s2 = random.normal(0.6, 0.12, size=N*(1-a)) s = np.concatenate([s1, s2]) ''' import matplotlib.pyplot as plt plt.hist(s, bins=20) plt.show() ''' # matplotlib.mlab.normpdf を用いて,混合確率密度を得る def pdf_model(x, p): mu1, sig1, mu2, sig2, pi_1 = p return pi_1 * mlab.normpdf(x, mu1, sig1) + (1-pi_1) * mlab.normpdf(x, mu2, sig2) # 繰返し回数を固定(本来は値が収束するまで反復) max_iter = 100 # パラメータの初期設定(テキトー?) p0 = np.array([-0.2, 0.2, 0.8, 0.2, 0.5]) mu1, sig1, mu2, sig2, pi_1 = p0 mu = np.array([mu1, mu2]) sig = np.array([sig1, sig2]) pi_ = np.array([pi_1, 1-pi_1]) gamma = np.zeros((2, s.size)) # 2 * サンプル数のゼロ行列 N_ = np.zeros(2) # サイズ 2 のゼロベクトル p_new = p0 # ここから EM ループ... counter = 0 converged = False while not converged: # Compute the responsibility function and new parameters for k in [0, 1]: # E-step gamma[k,:] = pi_[k] * mlab.normpdf(s, mu[k], sig[k]) / pdf_model(s, p_new) # M-step N_[k] = 1. * gamma[k].sum() mu[k] = sum(gamma[k] * s) / N_[k] sig[k] = np.sqrt(sum(gamma[k] * (s - mu[k])**2) / N_[k]) pi_[k] = N_[k] / s.size p_new = [mu[0], sig[0], mu[1], sig[1], pi_[0]] # assert abs(N_.sum() - N) / float(N) < 1e-6 # assert abs(pi_.sum() - 1) < 1e-6 counter += 1 converged = counter >= max_iter print "parameters : ", p_new
実行結果を以下に示す。
parameters : [0.0063749972625032486, 0.076249720004177929, 0.60298724972290296, 0.11940589580298418, 0.30040038558122012]
サンプル生成の際に仮定した密度関数のパラメータを推定できているようだ。
次に scikit learn を用いた実装を試した。
import numpy as np from numpy import random from sklearn import mixture np.random.seed(1) # 2つの正規分布を重み (0.3, 0.7) で混合する N=1000 a=0.3 s1 = random.normal(0, 0.08, size=N*a) s2 = random.normal(0.6, 0.12, size=N*(1-a)) s = np.concatenate([s1, s2]) #s = np.vstack(s) clf = mixture.GMM(n_components=2, covariance_type='diag') clf.fit(s) print "weight : ", clf.weights_ print "mean : ", clf.means_ print "sigma : ", np.sqrt(clf.covars_)
sklearn を用いた場合の実行結果を以下に示す。
weight : [ 0.69922406 0.30077594] mean : [[ 0.60316138] [ 0.00671512]] sigma : [[ 0.12332669] [ 0.08305453]]
ほぼ同じ値に落ち着いた。
2次元正規密度関数のヒートマップ
Simon J.D. Prince, Computer vision: models, learning and inference (2012) に頻繁に出てくるヒートマップに刺激されて真似てみた。
#coding: utf-8 import numpy as np import matplotlib.pyplot as plt import matplotlib.mlab as mlab def main(): x = np.linspace(-4.0, 4.0, 200) y = np.linspace(-4.0, 4.0, 200) X, Y = np.meshgrid(x, y) # 2次元正規分布 # matplotlib.mlab : MATLAB compatible command # matplotlib.mlab.bivariate_normal(X, Y, sigmax=1.0, sigmay=1.0, mux=0.0, muy=0.0, sigmaxy=0.0) # spherical covariance # Z = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0, 0.0) # diagonal covariance Z = mlab.bivariate_normal(X, Y, 2.0, 1.0, 0.0, 0.0, 0.0) # ヒートマップ plt.pcolor(X, Y, Z, cmap=plt.cm.hot) plt.colorbar() # タイトル plt.title('bivariate normal density') # ラベル plt.xlabel('$x$', size=12) plt.ylabel('$y$', size=12) plt.show() if __name__ == '__main__': main()
描画されたヒートマップを以下に示す。
scipy を用いた Latent semantic indexing
#coding: utf-8 import numpy as np from scipy import linalg ''' Latent semantic indexing ''' def main(): # P.Baldi et al., 確率モデルによるWebデータ解析法, 森北出版, pp.96-98 に # 掲載されている行列を用いる X = np.matrix([[1,1,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,0,0,0,0,0,0], [0,0,0,1,1,1,0,0,0,0,0], [0,1,1,1,0,0,0,0,0,0,0], [1,0,0,0,0,1,1,0,0,0,0], [0,0,0,0,0,0,0,1,1,0,0], [0,0,0,0,0,0,0,0,0,1,2], [0,0,0,0,0,0,1,0,0,1,0], [0,0,0,0,0,0,0,0,1,1,0], [0,0,0,0,0,0,0,1,0,0,1]]) # scipy.linalg.svd # http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.svd.html u, sigma, v = linalg.svd(X) rank = np.shape(X)[0] u = np.matrix(u) # linalg.svd() の結果,sigma には特異値のリスト(降順)が返ってくるため # linalg.diagsvd を用いて行列に変換する # http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.diagsvd.html sigma = np.matrix(linalg.diagsvd(sigma, rank, rank)) v = np.matrix(v) # 特異値の大きい方から2個をとって X を再構成 z = 2 u2 = u[:, :z] sigma2 = sigma[:z, :z] v2 = v[:z, :] Xhat = u2 * sigma2 * v2 print Xhat np.savetxt('result.txt', Xhat, fmt='%.02f') if __name__ == '__main__': main()
実行結果は以下のとおり:
[[ 1.18742376e-01 1.48468092e-01 1.02079902e-01 3.36802551e-01 2.34722649e-01 2.07746172e-01 9.14487067e-02 -2.08551485e-03 3.41743214e-03 2.40646404e-02 6.94193966e-04] [ 2.52738635e-01 3.18786565e-01 2.19455902e-01 7.23753688e-01 5.04297787e-01 4.44151468e-01 1.87007032e-01 -2.02395303e-02 -4.72794523e-03 1.21686493e-02 -5.85747967e-02] [ 3.45097561e-01 4.34173811e-01 2.98781826e-01 9.85492384e-01 6.86710559e-01 6.05672638e-01 2.58391353e-01 -2.13348466e-02 -1.66967515e-03 3.21884065e-02 -5.60326060e-02] [ 2.59749943e-01 3.27600603e-01 2.25520701e-01 7.43758428e-01 5.18237727e-01 4.56451866e-01 1.92276046e-01 -2.06330486e-02 -4.73153071e-03 1.29213297e-02 -5.95614097e-02] [ 1.87913028e-01 2.30024227e-01 1.57670040e-01 5.20783588e-01 3.63113547e-01 3.25264417e-01 1.58277142e-01 2.47446747e-02 2.67106562e-02 1.07397837e-01 1.07687758e-01] [ 6.67965446e-03 -5.34773717e-03 -5.02206960e-03 -1.49947726e-02 -9.97270298e-03 1.96295375e-03 4.28127228e-02 7.78060127e-02 5.93812774e-02 1.93945477e-01 2.96197591e-01] [ 4.62012230e-02 -2.07481947e-02 -2.19752154e-02 -6.34780797e-02 -4.15028644e-02 2.51041386e-02 2.51467991e-01 4.45785034e-01 3.40555624e-01 1.11315083e+00 1.69762265e+00] [ 6.18128209e-02 5.37005262e-02 3.46060061e-02 1.16890844e-01 8.22848376e-02 9.14040781e-02 1.12458081e-01 1.33074100e-01 1.03684099e-01 3.44110267e-01 5.10254277e-01] [ 2.34484339e-02 4.03363860e-03 2.90538891e-04 3.86562148e-03 3.57508259e-03 2.30780273e-02 8.75820325e-02 1.43408667e-01 1.09918087e-01 3.60212333e-01 5.46747060e-01] [ 1.59795054e-02 -1.73708263e-02 -1.56109790e-02 -4.72126530e-02 -3.16016740e-02 1.44687434e-03 1.15006052e-01 2.12170201e-01 1.61833403e-01 5.28322325e-01 8.07542678e-01]]
読みづらいから,小数点以下2桁で表示すると次のようになる。
0.12 0.15 0.10 0.34 0.23 0.21 0.09 -0.00 0.00 0.02 0.00 0.25 0.32 0.22 0.72 0.50 0.44 0.19 -0.02 -0.00 0.01 -0.06 0.35 0.43 0.30 0.99 0.69 0.61 0.26 -0.02 -0.00 0.03 -0.06 0.26 0.33 0.23 0.74 0.52 0.46 0.19 -0.02 -0.00 0.01 -0.06 0.19 0.23 0.16 0.52 0.36 0.33 0.16 0.02 0.03 0.11 0.11 0.01 -0.01 -0.01 -0.01 -0.01 0.00 0.04 0.08 0.06 0.19 0.30 0.05 -0.02 -0.02 -0.06 -0.04 0.03 0.25 0.45 0.34 1.11 1.70 0.06 0.05 0.03 0.12 0.08 0.09 0.11 0.13 0.10 0.34 0.51 0.02 0.00 0.00 0.00 0.00 0.02 0.09 0.14 0.11 0.36 0.55 0.02 -0.02 -0.02 -0.05 -0.03 0.00 0.12 0.21 0.16 0.53 0.81
Windows form application でタイマーを使う
目的:一定の時間間隔ごとに特定の処理を行いたい。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace timer { public partial class Form1 : Form { int value = 0; public Form1() { InitializeComponent(); eventTimer.Interval = 1000; // 1000ミリ秒間隔 eventTimer.Tick += new System.EventHandler(eventTimer_Tick); eventTimer.Enabled = true; button1.Text = "Disable timer"; } private void Form1_Load(object sender, EventArgs e) { } private void eventTimer_Tick(object sender, EventArgs e){ value += 1; textBox1.Text = value.ToString(); } private void button1_Click(object sender, EventArgs e) { if(eventTimer.Enabled == true){ eventTimer.Enabled = false; button1.Text = "Enable timer"; } else { eventTimer.Enabled = true; button1.Text = "Disable timer"; } } } }
Kinect のスケルトン情報を取得&表示
スケルトン情報の取得に関するサンプルが沢山あるのだけれど,表示については(pygame の例はあれど)OpenCV のみで対処したサンプルが見つからず。
こんなのでよいのかしら?
import cv2 import numpy as np import pykinect from pykinect import nui import thread import sys # Video def video_frame_ready( frame ): if videoDisplay == False: return with screenLock: video = np.empty( ( 480, 640, 4 ), np.uint8 ) frame.image.copy_bits( video.ctypes.data ) if skeletons is not None: for index, data in enumerate(skeletons): if data.eTrackingState != nui.SkeletonTrackingState.TRACKED: continue #get right hand position handRightPosition = data.SkeletonPositions[nui.JointId.HandRight] hr = nui.SkeletonEngine.skeleton_to_depth_image(handRightPosition, 640, 480) #get left hand position handLeftPosition = data.SkeletonPositions[nui.JointId.HandLeft] hl = nui.SkeletonEngine.skeleton_to_depth_image(handLeftPosition, 640, 480) print "(%d, %d)" % (int(hr[0]), int(hr[1])) cv2.circle(video, (int(hr[0]), int(hr[1])), 20, (255, 0, 0), thickness=10) cv2.circle(video, (int(hl[0]), int(hl[1])), 20, (0, 0, 255), thickness=10) cv2.imshow( 'frame', video ) # Depth def depth_frame_ready( frame ): if videoDisplay == True: return depth = np.empty( ( 240, 320, 1 ), np.uint16 ) frame.image.copy_bits( depth.ctypes.data ) print skeletons if skeletons is not None: for index, data in enumerate(skeletons): if data.eTrackingState != nui.SkeletonTrackingState.TRACKED: continue #get head position headPosition = data.SkeletonPositions[nui.JointId.Head] hp = nui.SkeletonEngine.skeleton_to_depth_image(headPosition, 320, 240) cv2.circle(depth, (int(hp[0]), int(hp[1])), 20, (255, 255, 255), thickness=10) cv2.imshow( 'frame', depth ) def skeleton_frame_ready(frame): global skeletons skeletons = frame.SkeletonData if __name__ == '__main__': screenLock = thread.allocate() videoDisplay = False kinect = nui.Runtime() skeletons = None #skeleton frame ready event handling #Reference : http://www.slideshare.net/pycontw/pykinect kinect.skeleton_engine.enabled = True kinect.skeleton_frame_ready += skeleton_frame_ready kinect.video_frame_ready += video_frame_ready kinect.depth_frame_ready += depth_frame_ready kinect.video_stream.open( nui.ImageStreamType.Video, 2, nui.ImageResolution.Resolution640x480, nui.ImageType.Color ) kinect.depth_stream.open( nui.ImageStreamType.Depth, 2, nui.ImageResolution.Resolution320x240, nui.ImageType.Depth ) cv2.namedWindow( 'frame', cv2.WINDOW_AUTOSIZE ) while True: #waitKey() returns ASCII code of the pressed key key = cv2.waitKey(33) if key == 27: # ESC break elif key == 118: # 'v' print >> sys.stderr, "Video stream activated" videoDisplay = True elif key == 100: # 'd' print >> sys.stderr, "Depth stream activated" videoDisplay = False cv2.destroyAllWindows() kinect.close()
UniDic の能力はいかほど?
UniDic という辞書がありまして,優秀だというので試してみました。
UniDic プロジェクト日本語トップページ - SourceForge.JP
レビューや Twitter 等で使用される口語表現がターゲットであり,所謂,表記ゆれ問題への対処に使えないかと検討している段階です。
- 例1:このハンバーグ,すげー美味しい。
「すげー」は「凄い」が語彙素であると正しく判定してくれる。
この コノ コノ 此の 連体詞 ハンバーグ ハンバーグ ハンバーグ ハンバーグ-hamburg 名詞-普通名詞-一般 , , 補助記号-読点 すげー スゲー スゴイ 凄い 形容詞-一般 形容詞 終止形-一般 美味しい オイシー オイシイ 美味しい 形容詞-一般 形容詞終止形-一般 。 。 補助記号-句点 EOS
- 例2:このハンバーグ,おいしいぃぃぃ。
「おいしいぃぃぃ」の解釈は難しいようです。
この コノ コノ 此の 連体詞 ハンバーグ ハンバーグ ハンバーグ ハンバーグ-hamburg 名詞-普通名詞-一般 , , 補助記号-読点 おいしい オイシー オイシイ 美味しい 形容詞-一般 形容詞終止形-一般 ぃ ぃ 補助記号-一般 ぃ ぃ 補助記号-一般 ぃ ぃ 補助記号-一般 。 。 補助記号-句点