Microsoft 翻訳 API (Microsoft Translator) を利用するための準備

Microsoft 翻訳 API (Microsoft Translator) を利用するための準備について,手順をまとめました。

目次
1.Microsoft アカウントの取得
2.Microsoft Azure Marketplace への登録 & 顧客ID (consumer ID)の取得
3.アプリケーションの登録 &顧客の秘密 (consumer secret)の取得
4.Microsoft Translator 利用権の取得


1.Microsoft アカウントの取得

https://login.live.com/
画面の指示に従ってアカウントを登録する。
(筆者はアカウントを有していたので,それを使う。ユーザIDは例のメールアドレス,パスワードは ****)

2.Microsoft Azure Marketplace への登録 & 顧客ID (consumer ID)の取得

まず,Microfot Azure Marketplace へサインイン。
f:id:ymuto109:20140818221845p:plain



サインイン後,姓名を登録し,続行ボタンをクリック。

f:id:ymuto109:20140818221904p:plain




Microsoft Windows Azure Marketplace 契約」への同意
ページ下部の「使用条件に同意します」をチェックした後,登録ボタンをクリック。

再び,Microsoft Azure Marketplace のトップページに戻るので,ページトップの「マイアカウント」をクリック。
→ プライマリアカウントキーおよび顧客 ID を確認する。

f:id:ymuto109:20140818221909p:plain



3.アプリケーションの登録 &顧客の秘密 (consumer secret)の取得

「マイアカウント」の中の「開発者」メニューにてアプリケーションを登録する。
クライアントID ・・・顧客IDを入力
(アプリケーションの)名前・・・適当な文字列
顧客の秘密・・・別途,保存しておく。(アプリケーション作成時に必要となる)
リダイレクトURI・・・Microsoft Translator を利用する場合,無効なURI を使うよう指示されているから,存在しない URI を入力。


f:id:ymuto109:20140818221859p:plain




下図のように登録されたアプリケーションが表示されれば OK。
なお,「顧客の秘密」は右側の「編集」ボタンをクリックすれば確認できる。また,アプリケーション名もいつでも変更可能。
f:id:ymuto109:20140818221856p:plain



4.Microsoft Translator 利用権の取得

https://datamarket.azure.com/browse/data?category=developerservices
から Microsoft Translator へ,
または直接,
https://datamarket.azure.com/dataset/bing/microsofttranslator
へ移動。

とりあえず金をかけたくないから,フリープランを選択する。(「サインアップ」をクリック)
f:id:ymuto109:20140818221849p:plain




「前述の公開元のオファー条件とプライバシー ポリシーを読み、内容に同意しました。」にチェックを入れて,「サインアップ」をクリック。

f:id:ymuto109:20140818221852p:plain



以上で Microsoft Translator を利用できるようになります。

Web へのアクセス

C# の勉強を進めないとならない状況に追い込まれた。
文法書を読むのが面倒だから,何か作ってみようという訳で Web にアクセスするプログラムを書いてみた。

using System;
using System.IO;
using System.Text; // for Encoding
//using System.Collections.Generic;
//using System.Linq;
//using System.Threading.Tasks;

using System.Net;  //for WebRequest

namespace CSweb
{
    class Program
    {
        static void Main(string[] args)
        {
            //Webサーバへ GET リクエストを送る
            WebRequest req = WebRequest.Create("http://www.ube-k.ac.jp/");

            //GETリクエストに対するレスポンスを取得
            WebResponse res = req.GetResponse();

            //レスポンスの中身をチェック
            //(メモ) headers を含め,レスポンスの中に encoding を示唆する情報は見当たらない。
            Console.WriteLine("ContentLength : {0}\n" +
                "ContentType : {1}\n" +
                "Headers : {2}\n" +
                "IsFromCache : {3}\n" +
                "IsMutuallyAuthenticated : {4}\n" +
                "ResponseUri : {5}\n" +
                "SupportsHeaders : {6}",
                res.ContentLength,
                res.ContentType,
                res.Headers,
                res.IsFromCache,
                res.IsMutuallyAuthenticated,
                res.ResponseUri,
                res.SupportsHeaders);

            //Webページの中身を読みだす
            Stream st = res.GetResponseStream();
            StreamReader sr = new StreamReader(st, Encoding.GetEncoding("Shift_JIS"));
            string html = sr.ReadToEnd();
            sr.Close();
            st.Close();

            Console.WriteLine(html);
        }
    }
}

PyKinect : RGBカメラと距離カメラ

PyKinectを用いて KinectRGBカメラと距離カメラからのストリーミングデータを表示する。
2つのカメラから得られるデータを同時に表示する方法が分からない。

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

    video = np.empty( ( 480, 640, 4 ), np.uint8 )
    frame.image.copy_bits( video.ctypes.data )
    #cv2.imshow( 'video', video )
    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 )
    #cv2.imshow( 'depth', depth )
    cv2.imshow( 'frame', depth )

if __name__ == '__main__':
    #screenLock = thread.allocate()

    videoDisplay = False

    kinect = nui.Runtime()

    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( 'video', cv2.WINDOW_AUTOSIZE )
    cv2.namedWindow( 'depth', cv2.WINDOW_AUTOSIZE )
    '''
    cv2.namedWindow( 'frame', cv2.WINDOW_AUTOSIZE )

    #
    while True:
        #waitKey() は ASCIIコードを返す
        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()

Tweet Entities を利用した短縮URLの伸長

Twitter 上のツイートに含まれる URL は t.co によって短縮されている(プログラム冒頭の例を参照)。オリジナルの URL は Tweet Entities に記載されているから,これを利用して伸長する。

Tweet Entities ・・・ https://dev.twitter.com/docs/tweet-entities

#coding: utf-8

# ツイートに含まれる短縮 URL (t.co) を entities 情報に基づいて伸長する。
# 例を以下に示す:
#置換前 : テスト(2013/01/17) : Yahoo http://t.co/Q0bCD94p と Google https://t.co/Iq66XDzR を比べると Google が好き。
#置換後 : テスト(2013/01/17) : Yahoo http://t.co/Q0bCD94p と Google https://www.google.co.jp/ を比べると Google が好き。
#
# 2013.01.17

import tweepy
import re

#短縮 URL の伸長
def expandUrl(tl):
    # 複数の URL が含まれる場合に備えてループを回す
    # (注) urls フィールドの値はリストのため,いずれにしてもループを回す必要あり。
    for url in tl.entities['urls']:
        if url is None: break	# urls の値が存在しない場合
        shortenUrl = url['url']	#短縮URL
        expandedUrl = url['expanded_url']	#伸長した(オリジナル)URL
        tl.text = re.sub(shortenUrl, expandedUrl, tl.text)
    return tl

consumer_key = 'consumer key'
consumer_secret = 'consumer secret'

# my access token から見る
oauth_token = 'oauth token'
oauth_token_secret = 'oauth token secret'

# auth オブジェクトの初期化
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)

# あらかじめ取得したOAuth tokenの設定
auth.set_access_token(oauth_token, oauth_token_secret)

# api オブジェクトの設定
api = tweepy.API(auth)

#ユーザタイムラインの取得 (include_entities=True がポイント)
userTimeline = api.user_timeline('screen name', include_entities=True)

for tl in userTimeline:
    print "伸長前 : " + tl.text.encode('utf-8')

    #短縮 URL の伸長
    tl = expandUrl(tl)

    print "伸長後 : " + tl.text.encode('utf-8')

nltk.TextCollection.tf_idf の使い方

nltk.text.TextCollection クラスの説明は以下にある:
http://nltk.googlecode.com/svn/trunk/doc/api/nltk.text.TextCollection-class.html

TF-IDF とは

  • TF(term frequency): 文書 d におけるトークン t の出現頻度
  • IDF(inverted document frequency) : 「コーパスに含まれる文書数 / トークン t が現れる文書数」の対数

TF-IDFはこれらの積であり,その値が大きいほど文書中でのトークン t の重要度が大きいと捉える。
(注意)nltk.TextCollection.tf_idf(term,text) における TF は相対頻度で与えられ,IDF では自然対数が用いられる。

例題

nltk.text.TextCollection.tf_idf の動作を検証するため,簡単な例題を用いて手計算で TF-IDF 値を求めておく。

対象とする文書は以下の3つ:

d1 : 明日, の, 天気, は, 晴れ
d2 : 今日, の, 天気, は, 曇
d3 : 昨日, の, 天気, は, 晴れ

各トークンの DF 値は以下のとおり:

df(明日)=1
df(今日)=1
df(昨日)=1
df(の)=3
df(天気)=3
df(は)=1
df(晴れ)=2
df(曇)=1

文書 d1 におけるトークン「明日」の TF-IDF 値の計算:

tf(明日, d1) = 1 / 5 = 0.2  ・・・nltk の tf は正規化されているため。
w(明日, d1) = 0.2 * log(3 / 1) = 0.2 * 1.0986123 = 0.21972246

同様に「晴れ」の値:

tf(晴れ, d1) = 1 / 5 = 0.2
w(晴れ, d1) = 0.2 * log(3 / 2) = 0.2 * 0.40546511 = 0.081093022

「天気」は全ての文書に出現するため,TF-IDF 値はゼロとなる。

tf(天気, d1) = 1 / 5 = 0.2
w(天気, d1) = 0.2 * log(3 / 3) = 0.0

nltk.text.TextCollection.tf_idf の利用

プログラムを以下に示す:

#coding: utf-8

import nltk

docs = [
    ['明日','の','天気','は','晴れ'],
    ['今日','の','天気','は','曇'],
    ['昨日','の','天気','は','晴れ']]

collection = nltk.TextCollection(docs)
uniqTerms = list(set(collection))

for doc in docs:
    print "===================="
    for term in uniqTerms:
        print "%s : %f" % (term, collection.tf_idf(term, doc))
    print "===================="

実行結果は次のようになり,手計算の結果と一致した。

====================
今日 : 0.000000
晴れ : 0.081093
天気 : 0.000000
昨日 : 0.000000
は : 0.000000
の : 0.000000
明日 : 0.219722
曇 : 0.000000
====================
====================
今日 : 0.219722
晴れ : 0.000000
天気 : 0.000000
昨日 : 0.000000
は : 0.000000
の : 0.000000
明日 : 0.000000
曇 : 0.219722
====================
====================
今日 : 0.000000
晴れ : 0.081093
天気 : 0.000000
昨日 : 0.219722
は : 0.000000
の : 0.000000
明日 : 0.000000
曇 : 0.000000
====================

Twitter において自分がよく使う語は何か?

自分のツイートに含まれる語の傾向を知るため,頻度分布を求めた。
手順は以下のとおり:

1.Twitter API を利用し,自らのタイムラインを取得する。(tweepy.API.user_timeline)

$ python mytweets.py > mytweets.txt

mytweets.py

#coding: utf-8

import tweepy

consumer_key = 'consumer key'
consumer_secret = 'consumer secret'
oauth_token = 'oauth token'
oauth_token_secret = 'oauth token secret'

# auth オブジェクトの初期化
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)

# あらかじめ取得したOAuth tokenの設定
auth.set_access_token(oauth_token, oauth_token_secret)

# api オブジェクトを設定
api = tweepy.API(auth)

# Twitter API を利用してユーザ・タイムラインを取得
statuses = api.user_timeline(count=100)

for status in statuses:
    print status.text.encode('utf-8')

サイズは 205件。(205件に深い意味はない)

$ wc ~/mytweets.txt 
  205   419 34915 /home/muto/mytweets.txt

2.取得したタイムライン中のテキスト(=つぶやき)を分かち書き

$ mecab -O wakati mytweets.txt > mytweets_wakati.txt

3.nltk.FreqDist を用いて,各語の頻度を求める。

$ python analysis.py

analysis.py

#coding: utf-8

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

import nltk
from nltk.corpus.reader import *
from nltk.corpus.reader.util import *
#from nltk.text import Text

corpus = nltk.corpus.reader.PlaintextCorpusReader('.', 'mytweets_wakati.txt', encoding='utf-8')

fd = nltk.FreqDist(corpus.words())

#頻度の出力
for k in fd.keys():
    print "%s : %d" % (k, fd[k])

#プロット
fd.plot(100)

(注)本来ならばストップワードを設定すべきだが,面倒だったから全ての語を対象とした。

頻度の降順にプロットした結果を以下に示す。
f:id:ymuto109:20121228003006p:plain

次に,手作業でストップワードを除去した結果を示す。(頻度4以上の語を抽出)

  • Twitter の特性上,「今日」が最大であった。また,「昨日」「明日」の出現頻度も高い。
  • 「今日」に続くのが「仕事」「時間」であり,なんだか時間に追われながら仕事しているようで悲しくなる。
  • "http" はリンクを貼りつけた結果であろう。オリジナルのポストでリンク貼り付けをやらないため,リツイートが影響したと考えられる。
  • その後,「問題」「学生」「テスト」と続くのは約2週間前に定期試験が行われたため。
  • 頻度が1桁の語からは,概ね,普段の仕事が透けて見えそうだ。
今日 : 21
仕事 : 19
時間 : 19
http : 15
問題 : 15
明日 : 15
学生 : 11
テスト : 10
昨日 : 10
考え : 10
今夜 : 9
会議 : 9
朝 : 9
調査 : 9
Google : 8
予定 : 8
企業 : 7
寮 : 7
採点 : 7
日本 : 7
メール : 6
就職 : 6
必要 : 6
自分 : 6
アカウント : 5
エアコン : 5
データ : 5
ネット : 5
メモ : 5
主事 : 5
気温 : 5
点検 : 5
研究 : 5
言葉 : 5
API : 4
TPP : 4
nltk : 4
ゴミ : 4
バス : 4
不安 : 4
予報 : 4
今朝 : 4
作成 : 4
作業 : 4
大変 : 4
大学生 : 4
政治 : 4
明確 : 4
社会 : 4
程度 : 4
管理 : 4
終了 : 4
試験 : 4
認証 : 4
資料 : 4
購入 : 4
身体 : 4
過去 : 4
部屋 : 4
関係 : 4
雨 : 4
頭 : 4

nltk.FreqDist および nltk.ConditionalFreqDist の plot() で日本語を出力させる方法

nltk.FreqDist クラスおよび nltk.ConditionalFreqDist クラスに含まれる plot() メソッドを利用した場合,軸(特に横軸)で日本語フォントが使えないという問題がある。
plot() メソッドでは内部的に matplotlib.pyplot を利用しており,日本語を出力するためには fontproperties を明示的に指定する必要がある。

以上の事情を踏まえ,nltk 自体に手を入れる。

対象とするファイル:
/usr/local/lib/python2.7/dist-packages/nltk/probability.py

probability.py 内の class FreqDist および class ConditionalFreqDist それぞれに
含まれる plot() メソッドを次のように書き換える。pylab.xticks() におけるパラメータ fontproperties の指定が肝である。
なお,フォント名は各自の環境に応じて変更すること。
(FreqDist クラスのみ示す。ConditionalFreqDist も同様に。)

def plot(self, *args, **kwargs):
    try:
        import pylab
    except ImportError:
        raise ValueError('The plot function requires the matplotlib package (aka pylab).'
                         'See http://matplotlib.sourceforge.net/')

    # code added : 2012.12.27 (from here)
    import sys
    import matplotlib.font_manager

    reload(sys)
    sys.setdefaultencoding('utf-8')
    fontprop = matplotlib.font_manager.FontProperties(fname='/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf')
    # code added : 2012.12.27 (up to here)

    if len(args) == 0:
        args = [len(self)]
    samples = list(islice(self, *args))
        
    cumulative = _get_kwarg(kwargs, 'cumulative', False)
    if cumulative:
        freqs = list(self._cumulative_frequencies(samples))
        ylabel = "Cumulative Counts"
    else:
        freqs = [self[sample] for sample in samples]
        ylabel = "Counts"
    # percents = [f * 100 for f in freqs]  only in ProbDist?
        
    pylab.grid(True, color="silver")
    if not "linewidth" in kwargs:
        kwargs["linewidth"] = 2
    if "title" in kwargs:
        pylab.title(kwargs["title"])
        del kwargs["title"]
    pylab.plot(freqs, **kwargs)
    # code changed : 2012.12.27
    #pylab.xticks(range(len(samples)), [str(s) for s in samples], rotation=90)
    pylab.xticks(range(len(samples)), [str(s).decode('utf-8') for s in samples], rotation=90, fontproperties=fontprop)

    pylab.xlabel("Samples")
    pylab.ylabel(ylabel)
    pylab.show()

最後に probability.py をコンパイルして,準備完了。

$ cd /usr/local/lib/python2.7/dist-packages/nltk/
$ sudo python -m compileall probability.py

conditionalFreqDist.plot() を実行した結果を以下に示す。
f:id:ymuto109:20121227133926p:plain