tag:blogger.com,1999:blog-24960148508338940632024-03-06T06:28:18.998+09:00hanzomemo研究やプログラミングなどのメモを中心に。Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-2496014850833894063.post-90905010848174057602016-11-16T14:10:00.001+09:002016-11-17T09:35:48.171+09:00Node.js+WebSocketでEnOceanセンサを扱う<h2>目的</h2>
Raspberry PiでEnOceanセンサデータを受信し、ブラウザ(localhost)上でリアルタイムに見れるようにしたい。<br />
WebSocketを扱う場合、PythonよりもNode.jsの方が簡単そうだったので実装してみた。<br />
<br />
Node.jsのバージョンはv6.9.1。今のところ、MacOS 10.12.1(Sierra)で動作を確認している。<br />
EnOceanの受信には<a href="https://www.npmjs.com/package/node-enocean">node-enocean</a>を利用。今回使っているのは以下4種類のセンサ。<br />
<ul>
<li>ドア開閉 (STM431J or CS-EO429J)</li>
<li>人感 (HM92-01WHC)</li>
<li>温度 (STM429J or CS-EO429J)</li>
<li>ロッカースイッチ (ESM210R)</li>
</ul>
<h2>実行例</h2>
EnOceanのセンサが動作すると、リアルタイムにdatetimeとstate欄の表示が更新される。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOz05zDy_yWC0emSboOdyqYse3fgTqIIikW0eKiQFn3-0aHrjq5VkAlJqtYuytyM-MitMjbyhl8vWR-TUJtlqJySMNRk8hXa_n5WetnoiXpwNwoWV71YNP904FY31Cg2vh8BtOeAiESv4R/s1600/screenshot.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOz05zDy_yWC0emSboOdyqYse3fgTqIIikW0eKiQFn3-0aHrjq5VkAlJqtYuytyM-MitMjbyhl8vWR-TUJtlqJySMNRk8hXa_n5WetnoiXpwNwoWV71YNP904FY31Cg2vh8BtOeAiESv4R/s320/screenshot.png" width="320" height="147" /></a>
<br />
<h2>ソースコード(サーバ側)</h2>
USBドングルのデバイス名(ここでは/dev/tty.usbserial-FTYKW2P5)とセンサIDは要変更。<br />
また、EnOceanプロトコルについては<a href="http://hanzomemo.blogspot.jp/2015/12/pythonenocean.html">以前の記事</a>を参照。<br />
<pre class="brush: js">
// execute at node.js v6.9.1
// サーバ設定
var fs = require("fs");
var http = require("http");
var socketio = require("socket.io");
var server = http.createServer( function(req, res) {
res.writeHead(200, {"Content-Type": "text/html" } );
var output = fs.readFileSync("index.html", "utf-8");
res.end(output);
}).listen(3000);
var io = socketio.listen(server);
// EnOcean設定
require("date-utils");
var enocean = require("node-enocean")();
enocean.listen("/dev/tty.usbserial-FTYKW2P5")
// サーバからデータ送信
io.sockets.on("connection", function (socket) {
// EnOceanの電文を受信
enocean.on("data", function (data) {
console.log("============================");
var dt = new Date();
var datetime = dt.toFormat("YYYY/MM/DD HH24:MI:SS");
console.log(datetime);
// 電文からdata部を抽出し、センサIDを取得
console.log("raw : "+data["rawByte"]); // 電文本体
body_length = parseInt(data["rawByte"].slice(4,6),16); // data部のbyte数
body = data["rawByte"].slice(12,12+body_length*2); // data部
sid = body.slice(2,10); // センサID
console.log("data : "+body);
console.log("sid : "+sid);
// センサの種類を識別して状態を取得
// ドア開閉 (STM431J or CS-EO429J)
if(sid=="0a007cd0"){
sType = "door";
if(body.slice(10,12)=="08") state = "open";
else if(body.slice(10,12)=="09") state = "close";
// 人感 (HM92-01WHC)
} else if(sid=="040150a5"){
sType = "motion";
if(body.slice(14,16)=="ff") state = "on";
else if(body.slice(14,16)=="00") state = "off";
// 温度 (STM429J or CS-EO429J)
} else if(sid=="040177db"){
sType = "temp";
val = parseInt(body.slice(14,16),16);
state = (255.0-val)/255.0*40.0;
// ロッカースイッチ (ESM210R)
} else if(sid=="002c865a"){
sType = "SW";
if(body.slice(10,12)=="84") state = "SW1-on";
else if(body.slice(10,12)=="88") state = "SW2-on";
else if(body.slice(10,12)=="04") state = "SW1-off";
else if(body.slice(10,12)=="00") state = "SW2-off";
} else {
sType = "unknown";
state = null
}
console.log("state : "+state);
// 送信用JSON作成
sensorStr = '{"datetime":"'+datetime+'","type":"'+sType+'","state":"'+state+'"}';
sensorJson = JSON.parse(sensorStr);
// WebSocketでJSONを送信
io.sockets.emit("sendLog", sensorJson);
});
});
</pre>
<h2>ソースコード(クライアント側)</h2>
<pre class="brush: html">
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Sample</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<table class="table">
<tr>
<th>type</th>
<th>datetime</th>
<th>state</th>
</tr>
<tr>
<td>door</td>
<td><div id="door-dt"></div></td>
<td><div id="door-state"></div></td>
</tr>
<tr>
<td>motion</td>
<td><div id="motion-dt"></div></td>
<td><div id="motion-state"></div></td>
</tr>
<tr>
<td>temp</td>
<td><div id="temp-dt"></div></td>
<td><div id="temp-state"></div></td>
</tr>
<tr>
<td>SW</td>
<td><div id="SW-dt"></div></td>
<td><div id="SW-state"></div></td>
</tr>
</table>
<script type="text/javascript">
var s = io.connect();
s.on("sendLog", function (data) {
sType = data["type"];
if(sType == "door"){
tgtId = "#door";
} else if(sType == "motion"){
tgtId = "#motion";
} else if(sType == "temp"){
tgtId = "#temp";
} else if(sType == "SW"){
tgtId = "#SW";
}
$(tgtId+"-dt").html(data["datetime"]);
$(tgtId+"-state").html(data["state"]);
});
</script>
</body>
</html>
</pre>
<h2>参考にしたサイト</h2>
<ul>
<li><a href="">node-enocean</a></li>
<li><a href="http://www.sandalot.com/node-jswebsocket%E3%81%AE%E5%AE%9F%E9%A8%93%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F/">Node.js+WebSocketの実験をしてみました | sand a lot Web & Music Create [札幌]</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-90273005586373922752016-06-21T17:19:00.002+09:002016-06-21T17:19:54.553+09:00scikit-learnで作成した分類器をエクスポートする<h2>目的</h2>
scikit-learnで作成した分類器(決定木/ランダムフォレスト)を、外部ファイルとしてエクスポートしたい。
つまり、他のプログラムで読み込める、scikit-learnやpythonを使わずとも実装できる形式で出力したい。<br />
<h2>決定木</h2>
作成した分類器をそのままexport_graphvizするだけ。<br />
<pre class="brush: python">
from sklearn.datasets import load_iris
from sklearn import tree
clf = tree.DecisionTreeClassifier()
iris = load_iris()
clf = clf.fit(iris.data, iris.target)
tree.export_graphviz(clf, out_file='tree.dot')
</pre>
<h2>ランダムフォレスト</h2>
そのままexport_graphvizすることはできず、一手間必要。<br />
ランダムフォレストで作成した分類器のclf.estimators_で決定木のリストを取得できるので、それぞれのリストに対して上記同様にexport_graphvizする。<br />
この場合、木の本数分dotファイルが生成される。下記の例では100本の木を作成するので、tree_0.dot~tree_99.dotが出力される。<br />
<pre class="brush: python">
from sklearn.datasets import load_iris
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100)
iris = load_iris()
clf = clf.fit(iris.data, iris.target)
for i,val in enumerate(clf.estimators_):
tree.export_graphviz(clf.estimators_[i], out_file='tree_%d.dot'%i)
</pre>
<h2>出力例</h2>
<pre class="brush: python">
digraph Tree {
0 [label="X[3] <= 0.8000\ngini = 0.666666666667\nsamples = 150", shape="box"] ;
1 [label="gini = 0.0000\nsamples = 50\nvalue = [ 50. 0. 0.]", shape="box"] ;
0 -> 1 ;
2 [label="X[3] <= 1.7500\ngini = 0.5\nsamples = 100", shape="box"] ;
0 -> 2 ;
3 [label="X[2] <= 4.9500\ngini = 0.168038408779\nsamples = 54", shape="box"] ;
2 -> 3 ;
4 [label="X[3] <= 1.6500\ngini = 0.0407986111111\nsamples = 48", shape="box"] ;
3 -> 4 ;
5 [label="gini = 0.0000\nsamples = 47\nvalue = [ 0. 47. 0.]", shape="box"] ;
4 -> 5 ;
6 [label="gini = 0.0000\nsamples = 1\nvalue = [ 0. 0. 1.]", shape="box"] ;
4 -> 6 ;
7 [label="X[3] <= 1.5500\ngini = 0.444444444444\nsamples = 6", shape="box"] ;
3 -> 7 ;
8 [label="gini = 0.0000\nsamples = 3\nvalue = [ 0. 0. 3.]", shape="box"] ;
7 -> 8 ;
9 [label="X[2] <= 5.4500\ngini = 0.444444444444\nsamples = 3", shape="box"] ;
7 -> 9 ;
10 [label="gini = 0.0000\nsamples = 2\nvalue = [ 0. 2. 0.]", shape="box"] ;
9 -> 10 ;
11 [label="gini = 0.0000\nsamples = 1\nvalue = [ 0. 0. 1.]", shape="box"] ;
9 -> 11 ;
12 [label="X[2] <= 4.8500\ngini = 0.0425330812854\nsamples = 46", shape="box"] ;
2 -> 12 ;
13 [label="X[1] <= 3.1000\ngini = 0.444444444444\nsamples = 3", shape="box"] ;
12 -> 13 ;
14 [label="gini = 0.0000\nsamples = 2\nvalue = [ 0. 0. 2.]", shape="box"] ;
13 -> 14 ;
15 [label="gini = 0.0000\nsamples = 1\nvalue = [ 0. 1. 0.]", shape="box"] ;
13 -> 15 ;
16 [label="gini = 0.0000\nsamples = 43\nvalue = [ 0. 0. 43.]", shape="box"] ;
12 -> 16 ;
}
</pre>
<h2>参考リンク</h2>
<ul>
<li><a href="http://scikit-learn.org/stable/modules/generated/sklearn.tree.export_graphviz.html">sklearn.tree.export_graphviz — scikit-learn 0.17.1 documentation</a></li>
<li><a href="http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html">3.2.4.3.1. sklearn.ensemble.RandomForestClassifier — scikit-learn 0.17.1 documentation</a></li>
<li><a href="http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html">3.2.4.3.2. sklearn.ensemble.RandomForestRegressor — scikit-learn 0.17.1 documentation</a></li>
<li><a href="http://stackoverflow.com/questions/16329384/random-forest-interpretation-in-scikit-learn">python - Random Forest interpretation in scikit-learn - Stack Overflow</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-75055711361423743212016-03-04T14:09:00.000+09:002016-03-04T14:09:01.992+09:00EnOceanセンサ記録(ドア開閉・人感・温度)<a href="http://hanzomemo.blogspot.jp/2015/12/pythonenocean.html">前回の記事</a>ではマグネットセンサSTM429Jと温度センサSTM431Jを読み取る例を載せた。<br />
先日、<a href="http://simics.co.jp/wordpress/wp-content/uploads/2016/02/%E4%BA%BA%E6%84%9F%E3%82%BB%E3%83%B3%E3%82%B5_20160215.pdf">サイミックス社製のEnOcean人感センサHM92-01WHC</a>を手に入れたので、上記と合わせ3つのセンサを家庭内(自宅ではないが)に配置してセンサログを取ってみることにした。<br />
マグネットと人感センサは玄関に、温度センサはリビングに配置した。<br /><br />
数日間の記録をpythonのmatplotlibを用いて可視化した結果が以下のとおり。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivDxWiiN0wjZY8d0QnkHqjt4pRufZxBCs6LKYdY-c5n6KgTl2epBQ3cqfrisFsLxNaaescnO9S8Z2pkJT_JweRR_ySGmFuaHWXZzmJZXc8UgYM_-ycS0Y1SkHBhCoNAOxfBiVKs6bREZp9/s1600/sensor_feb.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivDxWiiN0wjZY8d0QnkHqjt4pRufZxBCs6LKYdY-c5n6KgTl2epBQ3cqfrisFsLxNaaescnO9S8Z2pkJT_JweRR_ySGmFuaHWXZzmJZXc8UgYM_-ycS0Y1SkHBhCoNAOxfBiVKs6bREZp9/s1600/sensor_feb.png" /></a>
<br /><br />
温度のヒートマップに、ドア開と人感の時刻を無理やり載せた。<br />
右のカラーバーは気温を表しており、それとは別にドア開は青、人感は赤で表示している。<br />
縦軸が時刻、横軸が日付。つまり縦1列が1日を表している。
<br /><br />
マグネットセンサの配置がまずかったのかドア開閉の欠落が多々あったものの、こうやって見ると、かなり詳しいレベルで生活パターンがわかってしまう。<br />
特に、冬ということもあって温度で活動の有無がはっきりと判別できる。取り扱い注意である。Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-80209996642225667222015-12-14T16:38:00.001+09:002016-06-22T11:01:47.188+09:00PythonでEnOceanの電文を読み取る太陽光で動作するEnOceanマグネットセンサSTM429J、温度センサSTM431Jを利用する際のメモ。<br />
Python2.7.9+pySerialで実装。<br />
<h2>ESP:EnOcean Serial Protocol</h2>
詳しいドキュメントは<a href="http://www.enocean.com/esp">EnOceanのサイトからDLできる</a>。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKQwE19xL44lq9BW8yS_rBdlHmXJuxhiPM8f5vJFKwoN4FKLA_2Jwlgtm_II05Wj60iFAqIuz021I3aojJMrWUsd2swP25lItoZkdoCjXKUl5Kly-pFgrwgSH60qPR4DxqJ396DSz9EulW/s1600/ESP3.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKQwE19xL44lq9BW8yS_rBdlHmXJuxhiPM8f5vJFKwoN4FKLA_2Jwlgtm_II05Wj60iFAqIuz021I3aojJMrWUsd2swP25lItoZkdoCjXKUl5Kly-pFgrwgSH60qPR4DxqJ396DSz9EulW/s1600/ESP3.png"></a><br />
EnOceanの電文は上記の図(ドキュメントから引用)のようになっている。<br />
<ol>
<li>Sync. Byte: 同期用の信号で、常に0x55で固定。</li>
<li>header: 4byte固定。2番目のbyteにdataの、3番目にoptional dataの長さが書かれている。</li>
<li>CRC8H: チェックサム。</li>
<li>data: センサIDや動作内容が記載されている。</li>
<ul>
<li>センサid: dataの2~5番目に書かれている4byte。</li>
<li>マグネットセンサ(STM429J): dataの6番目のbyteが0x08なら開、0x09なら閉。</li>
<li>温度センサ(STM431J): dataの8番目のbyteを元に算出する。例えば5dなら25.4℃。<br />temp = (255.0-val)/255.0*40.0</li>
</ul>
<li>optional data: 長さはheaderに書かれている。</li>
<li>CRC8D: チェックサム。</li>
</ol>
<h2>Pythonのソースコード</h2>
CentOS環境でPython2.7.9/pySerialにより実装した例。<br />
シリアル通信で1byteずつ読み取る。<br />
電文の先頭はかならず0x55になるので、それを起点としてカウントする。<br />
<pre class="brush: python">
# coding: UTF-8
from serial import *
from sys import exit
from datetime import datetime
port = '/dev/ttyUSB0'
# シリアルポートを開く
try:
ser = Serial(port, 57600)
print('open serial port: %s' % port)
except:
print('cannot open serial port: %s' % port)
exit(1)
# 初期化
cnt,dataLen,optLen = 0,0,0
telegraph,headList,dataList,optList = [],[],[],[]
ready = True # 電文開始のフラグ管理
# データの解釈とログの記録
while True:
s = ser.read().encode('hex') # 1byteずつ読み込み
if s == '55' and ready: # 電文開始
# 変数のリセット
cnt,dataLen,optLen = 0,0,0
telegraph,headList,dataList,optList = [],[],[],[]
ready = False
print '=========='
cnt += 1
telegraph.append(s)
if 2 <= cnt <= 5: # header
headList.append(s)
if cnt == 5: # header終了, data length取得
dataLen = int(headList[1],16)
optLen = int(headList[2],16)
if 7 <= cnt <= (6+dataLen): # data
dataList.append(s)
if (7+dataLen) <= cnt <= (6+dataLen+optLen): # optional data
optList.append(s)
if cnt == (6+dataLen+optLen+1): # 電文終了
ready = True
dt = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# ログ出力
print dt
print ':'.join(telegraph)
print 'head...', ':'.join(headList)
print 'data...', ':'.join(dataList), '(length=%d)' % dataLen
print 'opt ...', ':'.join(optList), '(length=%d)' % optLen
sensorId = ':'.join(dataList[1:5]) # センサID取得
print 'sid ...', sensorId
# マグネットセンサ
if sensorId == '04:00:03:df':
if dataList[5] == '08':
action = 'open'
elif dataList[5] == '09':
action = 'close'
print 'door...', action
# 温度センサ
elif sensorId == '04:00:7a:fc':
val = int(dataList[7],16)
temp = (255.0-val)/255.0*40.0
print 'temp...', temp
# 上記以外のセンサIDは無視
else:
continue
</pre>
出力結果は以下のとおり。<br />
今のところ変な挙動もなく、ドア開閉や気温をきちんと読み取れている。<br />
<pre class="brush: bash">
open serial port: /dev/ttyUSB0
==========
2015-12-14 16:12:58
55:00:07:02:0a:0a:21:04:00:03:df:08:61:01:3a:b3
head... 00:07:02:0a
data... 21:04:00:03:df:08:61 (length=7)
opt ... 01:3a (length=2)
sid ... 04:00:03:df
door... open
==========
2015-12-14 16:13:05
55:00:07:02:0a:0a:21:04:00:03:df:09:66:01:3a:b3
head... 00:07:02:0a
data... 21:04:00:03:df:09:66 (length=7)
opt ... 01:3a (length=2)
sid ... 04:00:03:df
door... close
==========
2015-12-14 16:17:32
55:00:0a:02:0a:9b:22:04:00:7a:fc:00:00:5d:08:3f:01:37:90
head... 00:0a:02:0a
data... 22:04:00:7a:fc:00:00:5d:08:3f (length=10)
opt ... 01:37 (length=2)
sid ... 04:00:7a:fc
temp... 25.4117647059
</pre>
当初、pySerialのreadline()で1行ずつ受信しようとしたら上手くいかなかった。<br />
面倒でもread()で1byteずつ読み取って、ヘッダ部分からデータ長など読み取りつつ処理する必要がある。<br />
<br />
----<br />
2016/6/21追記:プログラムにバグがあるという指摘を受けて修正。Bool型変数readyによる、電文開始フラグに関する処理を追加した。
Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-72130231398112131012015-10-05T18:17:00.000+09:002016-02-02T14:43:30.698+09:00EnOceanのマグネットセンサSTM429Jでドア開閉検出
<a href="http://hanzomemo.blogspot.jp/2015/12/pythonenocean.html">PythonでEnOceanの電文を読み取る</a> に統合しました。Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-64839559730627469812015-09-08T14:10:00.004+09:002015-09-08T14:23:40.505+09:00赤外線センサをArduino経由のシリアル通信で受信するArduinoに赤外線センサ<a href="http://akizukidenshi.com/catalog/g/gM-02471/">SE-10</a>を接続し、Raspberry Piで読み取ってみた。<br />
<h2>今回使ったもの</h2>
<ul>
<li>Arduino UNO</li>
<li>人感センサSE-10</li>
<li>抵抗器:330Ω,10kΩ</li>
<li>赤色LED</li>
<li>ピンヘッダ (3pin):SE-10をブレッドボードに繋ぐため</li>
<li>Raspberry Pi</li>
</ul>
<h2>配線図</h2>
fritzingで配線図を描いてみる。<br />
SE-10側に10kΩ、LEDに330Ωの抵抗を繋ぐ。<br /><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM_Pi83OM5G19C91tb5AirfNndddDP4rsqTt0nEO0aQESvFBtUOHTai4mTALkOrEZJdulKy0wLzN97dtEjynsbbBhkp9Ef62RRToFuQI2XO8ZUNT8B7u0wNGESFxN4xKSr8MIPGaYHcsUy/s1600/arduino-SE10.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM_Pi83OM5G19C91tb5AirfNndddDP4rsqTt0nEO0aQESvFBtUOHTai4mTALkOrEZJdulKy0wLzN97dtEjynsbbBhkp9Ef62RRToFuQI2XO8ZUNT8B7u0wNGESFxN4xKSr8MIPGaYHcsUy/s320/arduino-SE10.png" /></a>
<h2>ソースコード</h2>
<h3>Arduino</h3>
センサが反応すると1を出力。<br />
反応後5秒間LEDが点灯し、その間は不感時間とする(チャタリング防止のため)。
<pre class="brush: cpp">
const int ledPin = 13;
const int pirPin = 2;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}
void loop() {
if (digitalRead(pirPin) == LOW) {
digitalWrite(ledPin, HIGH);
Serial.println("1");
delay(5000); //不感帯を5秒に設定
} else {
digitalWrite(ledPin, LOW);
}
delay(100);
}
</pre>
<h3>Python</h3>
要<a href="http://pyserial.sourceforge.net/">pySerial</a>。<br />
ArduinoのUSBデバイス名は/dev/ttyACM0。これはdmesg等で確認できる。<br />
センサが感知すると、時刻と共に出力される。<br />
<pre class="brush: python">
# coding: UTF-8
from serial import *
from sys import exit
from datetime import datetime
# ArduinoのUSBデバイス名
port = '/dev/ttyACM0'
# シリアルポートを開く
try:
ser = Serial(port, 9600)
print('open port: %s' % port)
except:
print('cannot open port: %s' % port)
exit(1)
# 読み出しと出力
while True:
# 1ライン単位で読み出し、末尾の改行コードを削除
line = ser.readline().rstrip()
try:
print(datetime.now(),line)
except Exception as e:
print(e.message)
</pre>
<h2>参考</h2>
<a href="http://n.mtng.org/ele/arduino/tutorial022.html">秋月電子の焦電型赤外線センサユニット(SE-10)を使う</a>Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-67514660087257470652015-08-13T16:05:00.000+09:002015-08-13T16:10:21.245+09:00加速度センサTWE-Lite-2525AのOTA(無線)による設定変更手順<a href="http://tocos-wireless.com/jp/products/TWE-Lite-USB/">ToCoStick</a>があれば、加速度センサ<a href="http://tocos-wireless.com/jp/products/TWE-Lite-2525A/">TWE-Lite-2525A</a>が検出する動作の種類(1回叩く・2回叩く・落とす・動かす)や感度を無線経由で設定できる。<a href="http://tocos-wireless.com/jp/products/TWE-Lite-R/">TWE-Lite R</a>を使えば有線で設定することも可能だが、配線が手間なので無線の方が簡単だ。<br />
ただ、メーカーの説明がややわかりづらいので、作業手順をメモしておく。
<br />
<h2>
用意するもの</h2>
<ul>
<li>TeraTermが動作するWindows PC</li>
<li>親機:ToCoStick</li>
<li>子機:TWE-Lite-2525A</li>
</ul>
<h2>
設定に必要なソフトウェア(バージョンは投稿時点のもの)</h2>
<ol>
<li><a href="http://tocos-wireless.com/jp/products/TWE-Lite-2525A/manual_settings.html">ToCoStick標準アプリケーション</a>
<ul>
<li>App_ToCoStick.exe</li>
<li>GUIでセンサの受信を確認できるWindows用アプリケーション</li>
</ul>
</li>
<li><a href="http://tocos-wireless.com/jp/tech/misc/LiteProg/index.html
">TWE-Liteプログラマ</a>
<ul>
<li>TWE-Programmer.exe</li>
<li>ToCoStickのアプリを切り替えるためのWindows用アプリケーション</li>
</ul>
</li>
<li><a href="http://tocos-wireless.com/jp/products/TWE-Lite-2525A/firmware_update.html">OTA設定用アプリ</a>
<ul>
<li>Samp_Monitor_EndDevice_Input_JN5164_CNFMST_1_5_3.bin</li>
<li>無線経由でTWE-Lite-2525Aの設定を変更するためのToCoStick用プログラム</li>
</ul>
</li>
<li><a href="http://tocos-wireless.com/jp/products/Software_download/index.html">超簡単!TWE標準アプリ</a>
<ul>
<li>App_TweLite_Master_JN5164_TOCOSTICK_1_6_6.bin</li>
<li>ToCoStickにデフォルトでインストールされている、センサ受信用プログラム</li>
</ul>
</li>
</ol>
<h2>メーカー情報</h2>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li><a href="http://tocos-wireless.com/jp/products/TWE-Lite-2525A/OTA.html" rel="nofollow">OTA設定(Over the Air) - TOCOS-WIRELESS.COM</a></li>
<li><a href="http://tocos-wireless.com/jp/products/TWE-Lite-2525A/manual_settings.html" rel="nofollow">IoT無線タグ TWE-Lite-2525A設定の詳細説明 - TOCOS-WIRELESS.COM</a></li></ul>
<h2>OTA設定手順</h2>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>ToCoStickをPCのUSBポートに挿す</li>
<li>「TWE-Liteプログラマ」を使ってOTA設定用アプリ(Samp_Monitor_EndDevice_Input_JN5164_CNFMST_1_5_3.bin)をToCoStickへ書き込む</li>
<li>「TWE-Liteのリセット」ボタンを押す</li>
<li>TeraTermでシリアル接続(設定>シリアルポートからボー・レートを115200に設定)</li>
<li>Enterキーを押すとメニューが出る
<pre class="brush: bash">--- CONFIG/Samp_Monitor V1-05-3/SID=xxxxxxxxx/LID=0x00/RC=10000 ---
a: set Application ID (0x67726305)
i: set Device ID (--)
c: set Channels (15)
x: set Tx Power (13)
d: set Sleep Dur (500)
w: set Sensor Wait Dur (0)
m: set Sensor Mode (0x35)
p: set Sensor Parameter (16)
P: set Sensor Parameter2 ()
k: set Enc Key (0xA5A5A5A5)
o: set Option Bits (0x00000011)
---
S: save Configuration
R: reset to Defaults
*** POWER ON END DEVICE NEAR THIS CONFIGURATOR ***</pre></li>
<li>例として、動作モードをActive/Inactive(動かした時・静止した時)のみ検出するように設定。
pを押してSensor Parameterを8と入力、SHIFT+sで記録。一瞬だけ下記のようなメッセージが出る。
<pre class="brush: bash">!INF FlashWrite Success
!INF RESET SYSTEM...</pre></li>
<li>Active/Inactiveモードの感度調整。<br />
大文字のP (Sensor Parameter2) を選んでTHA(動作のしきい値1~15000mg、初期値は2000)とTHI(静止のしきい値1~15000mg、初期値は1938)を指定。<br />
例えばそれぞれ1000,950ならTHA=1000,THI=950と入力。同様にSHIFT+sで記録。</li>
<li>設定の入力を終えたら、電池を抜いたTWE-Lite-2525AをToCoStickに近づけ、電池を入れる。すると下記メッセージが出てTWE-Lite-2525Aへの設定が完了。
<pre class="brush: bash">!INF REQUEST CONF FR 81020950
>>> TxCmp Ok(tick=35040,req=#0) <<<
!INF ACK CONF FR 81020950
SUCCESS 81020950</pre></li>
<li>ToCoStickに再度「超簡単!TWE標準アプリ(App_TweLite_Master_JN5164_TOCOSTICK_1_6_6.bin)」を書き込み、リセット</li>
</ol>
あとは<a href="http://hanzomemo.blogspot.jp/2015/08/raspberry-pitwe-lite-2525atocostick.html">前回の記事</a>にしたがってシリアル通信を行えば、指定した動作のみ受信できるようになる。<br /><br />
しかし、手順7に載せた感度調整パラメータを指定すると、何故か動作を認識しなくなってしまう。<br />
理由は不明だが、以下のtweetによればプログラムに問題があるようで、現状ではデフォルトの感度のまま利用するしかなさそうだ。
<blockquote class="twitter-tweet" data-conversation="none" lang="ja"><p lang="ja" dir="ltr">TWE-Lite-2525AのADXL345.cのコードみてる。インタラクティブモードで適切な値を設定するのは無理な気がする。特に動き検出の感度を設定するTHAとTHIは /625*10 じゃなくて *10/625 にしないと…。とりあえずPは未設定にしておくのをおすすめ。</p>— ミクミンP/Kazuhiro Sasao (@ksasao) <a href="https://twitter.com/ksasao/status/576731489049571328">2015, 3月 14</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-76418510159243603772015-08-09T19:01:00.000+09:002015-08-13T15:53:25.372+09:00Raspberry Pi上でTWE-Lite-2525AからのデータをToCoStickを使って受信するRaspberry Piに<a href="http://tocos-wireless.com/jp/products/TWE-Lite-USB/">ToCoStick</a>を繋いで、加速度センサ<a href="http://tocos-wireless.com/jp/products/TWE-Lite-2525A/">TWE-Lite-2525A</a>から送られてきた情報をシリアル通信でモニタリングするために行った作業のメモ。<br />
ToCoStickのアプリはデフォルト(超簡単!TWEアプリ)のまま利用。<br />
<br />
Raspberry PiのUSBポートにToCoStickを挿し、dmesgを確認。ttyUSB0として認識されたようだ。<br />
<pre class="brush: bash">
user@raspberrypi ~ $ dmesg
(中略)
[ 554.996366] usb 1-1.2: Product: TWE-Lite-USB
[ 554.996382] usb 1-1.2: Manufacturer: TOCOS
[ 554.996398] usb 1-1.2: SerialNumber: XXXXXXXX
[ 555.003578] ftdi_sio 1-1.2:1.0: FTDI USB Serial Device converter detected
[ 555.003774] usb 1-1.2: Detected FT232RL
[ 555.004697] usb 1-1.2: FTDI USB Serial Device converter now attached to ttyUSB0
</pre>
シリアル通信を行うため、cuコマンドを使えるようにする。<br />
しかし、Raspberry Piの初期ユーザであるpi以外で接続を試みると、権限がないと言われてしまう。<br />
<pre class="brush: bash">
user@raspberrypi ~ $ sudo apt-get install cu
user@raspberrypi ~ $ cu -l /dev/ttyUSB0 -s 115200
cu: open (/dev/ttyUSB0): Permission denied
cu: /dev/ttyUSB0: Line in use
</pre>
どうやら、シリアルポートはdialoutというグループに属していないと一般ユーザはもちろん、rootであっても利用できないようだ(初期ユーザであるpiは登録されているので使える)。なので使用しているユーザを追加してやる。
<pre class="brush: bash">
user@raspberrypi ~ $ sudo vigr
- dialout:x:20:pi
+ dialout:x:20:root,user
</pre>
すると「整合性を保つために /etc/gshadow を変更する必要があるかもしれません。」とメッセージが出る。なので/etc/gshadowも同じように修正する。<br />
<pre class="brush: bash">
user@raspberrypi ~ $ sudo vim /etc/gshadow
- dialout:x:20:pi
+ dialout:x:20:root,user
</pre>
一度ログアウトし、再度cuコマンドで接続。無事接続され、TWE-Lite-2525Aを叩いたり動かすとログが出力される。ちなみにシリアル通信を終了させるには~.と入力する。Ctrl+Cでは終了できない。<br />
<pre class="brush: bash">
user@raspberrypi ~ $ cu -s 115200 -l /dev/ttyUSB0
Connected.
:788115017B81020950002F2C000BCD00080F403C3A5E5EDE
:788115018A81020950002F34000BCD00010F3E3E3A5E66C6
:788115018A81020950002F3C000BCD00000F3E3E3A5E56CF
:788115017881020950002F44000BCD00000F3E3E3A5E56D9
~.
Disconnected.
</pre>
続いて、公式で用意されている<a href="http://tocos-wireless.com/jp/tech/misc/python_twelite/index.html">Pythonによる読み出しスクリプト</a>を動かしてみる。<br />
<br />
このスクリプト(twelite_read.py)は引数に指定したポートへ接続し、TWE-Lite標準アプリの出力を整理して表示してくれる。<br />
<pre class="brush: bash">
user@raspberrypi ~/python $ python twelite_read.py /dev/ttyUSB0
open serial port: /dev/ttyUSB0
:788115019081020950002F64000BC500010F3E3E3A5E56A8
command = 0x81 (data arrival)
src = 0x78
src long = 0x81020950
dst = 0x00
pktid = 0x15
prtcl ver = 0x01
LQI = 144 / -48.10 [dbm]
time stmp = 189.562 [s]
relay flg = 0
volt = 3013 [mV]
DI1=1/1 DI2=0/1 DI3=0/1 DI4=0/1
AD1=1000 AD2=0996 AD3=0932 AD4=1508 [mV]
</pre>
DI0~4はそれぞれ下記の動作に対応している。上記の例ではDI1が1/1になっているので、TWE-Lite-2525Aを1回叩いたことを意味している。<br />
<ul>
<li>DI1: 軽く1回叩く</li>
<li>DI2: 軽く2回叩く</li>
<li>DI3: 落とす(50cm~?)</li>
<li>DI4: 動かす</li>
</ul>Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-37920808593760405152015-07-02T11:49:00.000+09:002016-06-21T17:20:27.787+09:00scikit-learnで作成した決定木をPDF形式で出力pythonの機械学習ライブラリscikit-learnで作成した決定木をPDF形式で出力する方法のメモ。<br />
環境はCentOS6.6、Python2.7.9。<br />
決定木を作成するコードは以下のサイトから。<br />
<br />
<a href="https://www.blogger.com/"></a><span id="goog_451191108"></span><span id="goog_451191109"></span><a href="http://todoa2c.github.io/blog/2014/08/12/writing-decision-tree/">Pythonで決定木を描いてみる - 技術情報棚卸し(平日限定)</a><br />
<br />
上記のサイトでは結果をgraph.dotというファイルに出力し、その後コマンドライン上でPDFへ変換している。これを毎回やるのは面倒なので、python内で処理してしまおうというのが目的。<br />
<br />
<pre class="brush: python"># encoding: utf-8
import pandas as pd
from sklearn import tree
from sklearn.externals.six import StringIO
from graphviz import Digraph
import pydot
data = pd.read_table('iris.txt')
# 説明変数
variables = ['Sepal.Length', 'Sepal.Width', 'Petal.Length', 'Petal.Width']
classifier = tree.DecisionTreeClassifier()
# 目的変数はSpecies
classifier = classifier.fit(data[variables], data['Species'])
# 結果をPDFで出力
dot_data = StringIO()
tree.export_graphviz(classifier, out_file=dot_data)
graph = pydot.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf('iris.pdf')
</pre>
<br />
実行してみると、以下のエラーが表示された。<br />
<pre class="brush: bash">Couldn't import dot_parser, loading of dot files will not be possible.
Traceback (most recent call last):
File "decision_tree.py", line 18, in <module>
graph = pydot.graph_from_dot_data(dot_data.getvalue())
File "/usr/local/lib/python2.7/site-packages/pydot.py", line 199, in graph_from_dot_data
return dot_parser.parse_dot_data(data)
NameError: global name 'dot_parser' is not defined</module></pre>
<br />
結論だけ書くとpydotをアンイストールしてpydot2を入れることで解決、無事PDFが作成された。
<br />
<pre class="brush: bash">$ sudo pip uninstall pydot
$ sudo pip install pydot2
</pre>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkhk36_Jds0zuXS-diS3H7-kbNX3WCE4PtH8T8wg2t4qzB39n6gzf4ske1MdOrT4rsNiGZEXXEIRQprtuO8PCymZ1jMKJudQN4Ceguyy9E7FWYy97Hjn93AczyhkZqbb0_DvrVJiFB-SPu/s1600/decision.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkhk36_Jds0zuXS-diS3H7-kbNX3WCE4PtH8T8wg2t4qzB39n6gzf4ske1MdOrT4rsNiGZEXXEIRQprtuO8PCymZ1jMKJudQN4Ceguyy9E7FWYy97Hjn93AczyhkZqbb0_DvrVJiFB-SPu/s320/decision.png"></a>
<br />
参考:
<ul>
<li><a href="http://scikit-learn.org/stable/modules/tree.html#classification">1.10. Decision Trees — scikit-learn 0.16.1 documentation</a></li>
<li><a href="http://infidea.net/troubleshooting-couldnt-import-dot_parser-loading-of-dot-files-will-not-be-possible/">[Troubleshooting] Couldn’t import dot_parser, loading of dot files will not be possible. | INFIDEA</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-85964151248162852602014-07-23T17:29:00.002+09:002014-07-23T23:01:30.459+09:00推薦システム勉強会で使用した文献を、まとめておく。
<br /><br />
<h2>
第1回</h2>
<ul>
<li><a href="http://www.kamishima.net/archive/recsysdoc.pdf">推薦システムのアルゴリズム</a></li>
<li>神嶌敏弘, 人工知能学会誌, Vol. 22, No. 6, pp. 826-837, 2007.</li>
<li>人工知能学会誌, Vol. 23, No. 1, pp. 89-103, 2008.</li>
<li>人工知能学会誌, Vol. 23, No. 2, pp. 248-263, 2008.</li>
</ul>
<br />
この分野ではお馴染みのサーベイ論文。基本から幅広く知識を習得できる。3回にわたって人工知能学会誌に掲載されたが、今は著者によりまとめられたものがWeb上に公開されている。<br /><br />
<h2>
第2-3回</h2>
<ul>
<li><a href="http://www-users.cs.umn.edu/~cosley/research/gl/evaluating-herlocker-tois2004.pdf">Evaluating collaborative filtering recommender systems</a></li>
<li>J. L. Herlocker, et al., ACM Transactions on Information Systems, Vol. 22, No. 1, pp. 5-53, 2004.</li>
</ul>
<br />
こちらも超有名なサーベイ論文で、10年前のものだが今でも十分通用する内容。推薦精度に関する評価指標を中心に紹介されている。精度以外の指標にも触れているが、確立された手法がなかったため簡単な言及に留めている(今でも確立されていないが)。<br /><br />
<h2>
第4回</h2>
<ul>
<li><a href="http://ceur-ws.org/Vol-835/paper12.pdf">Movie Recommendation with DBpedia</a></li>
<li>R. Mirizzi, et al., IIR, pp. 101-112, 2012.</li>
</ul>
<br />
Wikipediaの情報をLOD (Linked Open Data) 形式で公開しているDBpediaを情報源として映画の推薦を行う手法。ジャンルや監督、出演俳優といった属性とその値を用いているところが特徴で、こういった内容ベース的なアプローチと構造化された情報を扱うDBpediaは相性が良い。<br /><br />
<h2>
第5回</h2>
<ul>
<li><a href="http://www.comp.hkbu.edu.hk/~lichen/download/UMAP13_Wang.pdf">Recommendation for New Users with Partial Preferences by Integrating Product Reviews with Static Specifications</a></li>
<li>F. Wang, et al., UMAP, pp. 281-288, 2013.</li>
</ul>
<br />
Amazonに投稿されているレビューから,カメラであれば重量や価格といった観点(=属性)に対する嗜好を抽出する。この既存ユーザの嗜好情報を用いて、完全に把握できていない新規ユーザの嗜好 (partial preference) の欠損値を補う手法。レビューの選択基準が不明瞭だが、新規ユーザに対する推薦精度改善手法として面白いアプローチ。<br /><br />
<h2>
第6回</h2>
<ul>
<li><a href="http://u.cs.biu.ac.il/~sarit/data/articles/rec025-azaria_Movie.pdf">Movie Recommender System for Profit Maximization</a></li>
<li>A. Azaria, et al., RecSys, pp. 121-128, 2013.</li>
</ul>
<br />
ユーザが好む(高く評価する)可能性が高いアイテムを推薦する、というのがほとんどの推薦システムにおいて目的となっている。その中で、この手法はサービス提供者(主に企業)の利益を最大化することを目的としている。価格(利益)の高い商品や、キャンペーンや在庫処分などの理由でとある商品を優先的に推薦する、というのは企業では既にある程度やっていることだとは思う。ただ、アカデミックな分野ではあまりこういった目的での手法は見られなかったので、面白い手法と思う。<br /><br />
<h2>
第7回</h2>
<ul>
<li><a href="http://www.cs.utexas.edu/~ml/papers/submit.pdf">Explaining Recommendations: Satisfaction vs. Promotion</a></li>
<li>M. Bilgic, et al., Beyond Personalization Workshop, IUI, Vol.5, 2005.</li>
</ul>
<br />
少し古い文献だが、推薦時に理由(なぜそのアイテムが推薦されたが)を併せて提示することでユーザの満足度向上を試みた手法。提案手法は3つあるが、そのなかのNeighbor Style Explanation(協調フィルタリングによる近傍ユーザの評価値分布を推薦理由としてユーザに提示する手法)において、ユーザがその評価に影響され推薦アイテムに対して高い評価をしがちであるという結果。この結果に対して、推薦理由の提示により高い評価に影響を受ける=推薦アイテムを過大評価することに繋がり満足度が低下する、という考察が興味深い。<br /><br />
<h2>
第8回</h2>
<ul>
<li><a href="http://losaltos.thlab.net/uploads/papers/HotelSearch-RecSys2012.pdf">Finding a Needle in a Haystack of Reviews: Cold Start Context-Based Hotel Recommender System</a></li>
<li>A. Levi, et al., RecSys, pp. 115-122, 2012.</li>
</ul>
<br />
ホテルに対するレビューを対象として、属性(立地、サービス、部屋など)への言及の度合いを自然言語処理により推定し、コンテキストベースの推薦に用いている手法。新規ユーザやアイテムに対して推薦精度が低下するcold-start問題への解決策として、コンテキストベースの推薦を行う手法は広く行われている。新規ユーザに対して特に有効なアプローチだが、いずれの手法もアイテムに対する情報が事前に十分得られていることが前提となっている。<br /><br />
<h2>
第9回</h2>
<ul>
<li><a href="http://dl.acm.org/citation.cfm?id=2043957">Item Popularity and Recommendation Accuracy</a> ※有料</li>
<li>H. Steck, et al., RecSys, pp. 125-132, 2011.</li>
</ul>
<br />
いわゆる「ロングテール」に着目し、不人気アイテムを推薦することに重きを置いた手法。タイトルにAccuracyとあるが精度の検証はせず、アイテムの人気度を考慮した再現率を評価指標としている。着眼点は面白いが、データセットを用いたオフライン実験で検証できる範囲は限られており、そのあたり限界を感じる。<br /><br />
Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-68507811542487500962014-02-06T14:28:00.000+09:002015-07-14T15:03:33.864+09:00情報推薦の研究に使えるデータセット海外・国内それぞれで公開されているデータセットをまとめました。<br />
情報推薦(推薦システム)に関する研究で利用することを想定し、アイテム(商品や映画等)とそれに対する評価情報がペアになっているものをピックアップしています。
<br />
<h2><海外></h2>
<h3>
GroupLens Dataset</h3>
<ul>
<li><a href="http://grouplens.org/datasets/movielens/">http://grouplens.org/datasets/movielens/</a></li>
<li>映画に対する5段階評価 (1-5)</li>
<li>100,000 / 1,000,000 / 10,000,000 ratings</li>
<li>1,000 / 6,000 / 72,000 users</li>
<li>1,700 / 4,000 / 10,000 movies</li>
</ul>
最も有名で、最も利用されているデータセット。<br />
データサイズは100k, 1M, 10Mの3種類が用意されている。<br />
<br />
<br />
<h3>
The Book-Crossing Dataset</h3>
<ul>
<li><a href="http://www.informatik.uni-freiburg.de/~cziegler/BX/">http://www.informatik.uni-freiburg.de/~cziegler/BX/</a></li>
<li>書籍に対する11段階評価 (0-10)</li>
<li>1,149,780 ratings</li>
<li>278,858 users</li>
<li>271,379 books</li>
</ul>
<a href="http://www.bookcrossing.com/">Book-Crossing</a>と呼ばれる「書籍に旅をさせる」プロジェクトから収集されたデータセット。<br />
<br />
<br />
<h3>
Yelp Dataset</h3>
<ul>
<li><a href="http://www.yelp.com/dataset_challenge/">http://www.yelp.com/dataset_challenge/</a></li>
<li>店舗に対する5段階評価 (1-5)</li>
<li>229,907 reviews</li>
<li>43,873 users</li>
<li>11,537 shop/restaurants </li>
</ul>
飲食店やお店に関するクチコミを掲載している<a href="http://www.yelp.com/">Yelp</a>のデータセット。利用には申請が必要。<br />
面白いのは業績に対する賞金が充実していること。例えば査読付き論文誌に掲載されると1,000ドル貰えるし、学生なら賞金5,000ドルのAwardもある。<br />
その他、与えられたテキストからカテゴリを予測するといったことも行える(<a href="https://github.com/Yelp/dataset-examples">詳細はGitHubのページで</a>)。
<br />
<br />
<h3>
EachMovie Dataset</h3>
<ul>
<li><a href="http://grouplens.org/datasets/eachmovie/">http://grouplens.org/datasets/eachmovie/</a></li>
<li>店舗に対する5段階評価 (1-5)</li>
<li>2,811,983 reviews</li>
<li>72,916 users</li>
<li>1,628 movies</li>
</ul>
MovieLensと並んでよく利用されていたが、現在は公開終了。
<br />
<br />
<h2><国内></h2>
<h3>
楽天データ公開</h3>
<ul>
<li><a href="http://rit.rakuten.co.jp/rdr/">http://rit.rakuten.co.jp/rdr/</a></li>
<li>楽天市場(みんなのレビュー):商品に対する5段階評価 (1-5)</li>
<li>楽天トラベル:ホテルに対する5段階評価、項目別評価あり (1-5)</li>
</ul>
大学・研究機関のみ利用可能で、事前申請が必要。<br />
様々なデータが公開されているが、情報推薦の分野で活用できそうのなのは楽天市場、楽天トラベル、GORA(ゴルフ場)に関する評価データ。
<br />
楽天市場(みんなのレビュー)は膨大なレビューが利用可能。しかし「レビューを書くと送料無料」といった施策の影響か、コピペレビューがとても多い上に評価が5(最高値)に大きく偏っている。そのため、これらを踏まえた前処理が必須。実際に行った前処理の結果については下記参照。<br />
[追記] <a href="http://www.fujipress.jp/finder/xslt.php?mode=present&inputfile=JACII001800030012.xml">楽天市場のレビューを用いた論文が無料でDLできます(要ID登録)</a>。<br />
<p>Zhongjie Mao, Shunichi Hattori and Yasufumi Takama, Analysis of Online Reviews for Evaluating Informative Reviews, SCIS&ISIS2012, W2-44-2, 2012.</p>
楽天トラベルではコピペは少ないが、それでも評価は(他セットとくらべて)好評寄りに偏っている。
<br /><br />
<h3>
SUSHI Preference Data Sets</h3>
<ul>
<li><a href="http://www.kamishima.net/sushi/">http://www.kamishima.net/sushi/</a></li>
<li>寿司に対する嗜好を5段階(0-4)と順位(1-10)で評価</li>
<li>5,000 users</li>
<li>100 items</li>
</ul>
寿司についての嗜好を調査したデータセット。詳細は下記の文献を参照。<br />
<p>T. Kamishima, Nantonac Collaborative Filtering: Recommendation Based on Order Responses, KDD2003, pp.583-588, 2003. [<a href="http://www.kamishima.net/archive/2003-p-kdd.pdf">PDF</a>]</p>
<br />
<br />
Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-38148602523996084512013-05-14T10:23:00.000+09:002013-05-15T15:38:02.478+09:00PassengerでRailsアプリケーションをデプロイPassengerを用いてRailsアプリケーションをサーバへデプロイする際に行ったことをメモ。<br />
サーバのOSはCentOS 6.4、DBはMySQL 5.6.10で、Passengerがインストールされていることを前提に。Passengerのインストールについては下記ページが参考になる。<br />
<br />
<a href="http://redmine.jp/tech_note/apache-passenger/">Apache上でRuby on Railsアプリケーションを動かす/Passenger(mod_rails for Apache)の利用</a><br />
<br />
<h2>
アプリケーションのアップロード</h2>
<div>
Apacheのドキュメントルート(/var/www/html/など)にフォルダごとFTPでアップロードする。httpd.confの設定を変えれば、他の場所にしても構わない。<br />
<br /></div>
<div>
<h2>
所有者を変更</h2>
</div>
<div>
Passengerはroot権限でrailsアプリケーションを動作させることができないので、chownコマンドでフォルダの所有者を変更する。</div>
<pre class="brush: bash">% chown -R username:group /var/www/html/RAILS_ROOT
</pre>
<br />
<h2>
database.ymlの設定</h2>
<div>
開発機とサーバ機でMySQLのソケットやユーザ名が異なる場合は、development(開発用)、test(テスト用)、production(本番用)それぞれについてdatabase.ymlを修正する必要がある。</div>
<div>
<br />
RAILS_ROOT/config/database.yml</div>
<pre class="brush: text">production:
adapter: mysql2
encoding: utf8
reconnect: false
database: railsapp_production
pool: 5
username: username
password: pass
socket: /tmp/mysql.sock
</pre>
<div>
修正する必用があるのは多くの場合、username/password/socket欄だろうか。<br />
mysql.sockの場所が分からないのであれば下記コマンドを実行する。パスワードを求められるので、指定したユーザに対応するパスワードを入力する。</div>
<pre class="brush: bash">% mysqladmin -u username -p version
</pre>
<div>
出力結果(下記11行目)にソケットの場所が表示されている。</div>
<pre class="brush: text">mysqladmin Ver 8.42 Distrib 5.6.10, for osx10.8 on x86_64
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Server version 5.6.10
Protocol version 10
Connection Localhost via UNIX socket
UNIX socket /tmp/mysql.sock
Uptime: 29 days 23 hours 20 min 24 sec
Threads: 3 Questions: 37312 Slow queries: 0 Opens: 100 Flush tables: 1 Open tables: 67 Queries per second avg: 0.014
</pre>
<br />
<h2>
mysql2アダプタをインストール</h2>
<div>
まずはMySQLの開発ライブラリをインストール。</div>
<pre class="brush: bash">% sudo yum install mysql-devel
</pre>
<div>
Gemfileに以下を記述。<br />
<br />
RAILS_ROOT/Gemfile
</div>
<pre class="brush: text">gem 'mysql2'
</pre>
<div>
その後でbundle installを実行。<br />
<br /></div>
<h2>
本番用データベースを作成</h2>
<div>
Passenger上で動くrailsアプリケーションは標準でproductionモードでの動作となるので、それに対応するデータベースをサーバ上で作成する必要がある。</div>
<pre class="brush: bash">% rake db:create RAILS_ENV=production
% rake db:migrate RAILS_ENV=production
</pre>
<div>
これで完了。</div>
Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-1643855447260785852013-05-13T12:35:00.000+09:002013-05-13T12:36:58.059+09:00TeXworksでBibTeXを扱うWindows版TeXworksでBibTeXを使う時に引っ掛かったのでメモ。<br />
<br />
デフォルトで用意されているBibTeXは欧文専用であり、日本語を利用するためにはpBibTeXを追加する必要がある。<br />
<h2>
Texworksの設定</h2>
Texworksを起動し、「編集」から「設定」を開いてタイプセットタブへ移動する。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7VKFz_S07Katp8DtDZyAylsHgTBOwjHpJrxtGrwLAgi1ntYgYGZGmhE_hITXJhpI_6THCDjaexzaDvLoAgnXS-MmkCm5uD5m1xzT3HEaBtcSHRdmi8tSnzpTbRf2TExBGzuJ3Zl_P5iTb/s1600/config.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7VKFz_S07Katp8DtDZyAylsHgTBOwjHpJrxtGrwLAgi1ntYgYGZGmhE_hITXJhpI_6THCDjaexzaDvLoAgnXS-MmkCm5uD5m1xzT3HEaBtcSHRdmi8tSnzpTbRf2TExBGzuJ3Zl_P5iTb/s320/config.png" width="320" /></a></div>
<br />
上記のように「タイプセットの方法」欄があるので、「+」ボタンを押して開いたウィンドウ「タイプセットの方法を設定する」にて下記のように入力する。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXMzBcxZcttu-uNc0bePYZ3v7bwp-36rwsNrU6q6ZPVgfZNXt9gIlpgaZ-hbxTmKhxVgsTGPmvfzZ_ylRELyi0ECgHkAcrf1Sx4zknn2gyN2FoqGsZJdZ1TA6o1qbIMIEbCQQWMjzYzK6g/s1600/config.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="211" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXMzBcxZcttu-uNc0bePYZ3v7bwp-36rwsNrU6q6ZPVgfZNXt9gIlpgaZ-hbxTmKhxVgsTGPmvfzZ_ylRELyi0ECgHkAcrf1Sx4zknn2gyN2FoqGsZJdZ1TA6o1qbIMIEbCQQWMjzYzK6g/s320/config.png" width="320" /></a></div>
<br />
これで、タイプセットのプルダウンからpBibTeXが選択できるようになる。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw_lnZWIOGLV3r1-w3g_v4Yw5NhseqZZlB50XNkN9-EnmB5L1lw3Uoef3UBpoZ3l-tW1gdIka_5M0WD81JEknRjxkrj8kTpviblpyn85bEo66Kri1gbi5t7ziu-6xShc0AlBNICGtkgnie/s1600/%E7%84%A1%E9%A1%8C.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw_lnZWIOGLV3r1-w3g_v4Yw5NhseqZZlB50XNkN9-EnmB5L1lw3Uoef3UBpoZ3l-tW1gdIka_5M0WD81JEknRjxkrj8kTpviblpyn85bEo66Kri1gbi5t7ziu-6xShc0AlBNICGtkgnie/s320/%E7%84%A1%E9%A1%8C.png" width="320" /></a></div>
<h2>
タイプセット手順</h2>
あとはBibTeX同様、下記手順でタイプセットを行う。<br />
<br />
<ol>
<li>pLatexでタイプセット</li>
<li>pBibTeXでタイプセット(.bblファイルが作成される)</li>
<li>もう一度pLatexでタイプセット(引用関係がリンクされる)</li>
</ol>
<br />
<h2>
参考:</h2>
<a href="http://oku.edu.mie-u.ac.jp/~okumura/texwiki/?TeXworks%2F%E8%A8%AD%E5%AE%9A%2FWindows#a883f235">TeXworks/設定/Windows - TeX Wiki</a><br />
<br />Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com2tag:blogger.com,1999:blog-2496014850833894063.post-48466063877614561382013-04-02T09:44:00.000+09:002013-04-02T09:44:21.707+09:00DBpedia日本語版:SPARQLをRubyから実行<a href="http://hanzomemo.blogspot.jp/2013/04/dbpedia_1.html">前回のSPARQL</a>をRubyから実行する。Rubyのバージョンは1.9.3。<br />
<br />
まずはgemをインストール。<br />
<pre class="brush: bash">% gem install linkeddata
% gem install sparql
</pre>
<br />
SPARQLをRubyで実行するコード。<br />
<pre class="brush: ruby">#-*- coding: utf-8 -*-
require "sparql/client"
client = SPARQL::Client.new("http://ja.dbpedia.org/sparql")
results = client.query("
SELECT ?resource ?title
WHERE {
<http://ja.dbpedia.org/resource/織田裕二> dbpedia-owl:wikiPageWikiLink ?resource .
?resource rdf:type dbpedia-owl:Film .
?resource rdfs:label ?title .
}
")
results.each do |solution|
puts "#{solution[:resource]} | #{solution[:title]}"
end
</pre>
結果は以下のとおり。<br />
<pre class="brush: bash">http://ja.dbpedia.org/resource/踊る大捜査線_THE_MOVIE | 踊る大捜査線 THE MOVIE
http://ja.dbpedia.org/resource/踊る大捜査線_THE_MOVIE_2_レインボーブリッジを封鎖せよ! | 踊る大捜査線 THE MOVIE 2 レインボーブリッジを封鎖せよ!
http://ja.dbpedia.org/resource/ホワイトアウト_(小説) | ホワイトアウト (小説)
http://ja.dbpedia.org/resource/湘南爆走族 | 湘南爆走族
http://ja.dbpedia.org/resource/県庁の星 | 県庁の星
http://ja.dbpedia.org/resource/彼女が水着にきがえたら | 彼女が水着にきがえたら
http://ja.dbpedia.org/resource/椿三十郎_(2007年の映画) | 椿三十郎 (2007年の映画)
http://ja.dbpedia.org/resource/BEST_GUY | BEST GUY
http://ja.dbpedia.org/resource/将軍家光の乱心_激突 | 将軍家光の乱心 激突
http://ja.dbpedia.org/resource/T.R.Y. | T.R.Y.
http://ja.dbpedia.org/resource/就職戦線異状なし | 就職戦線異状なし
http://ja.dbpedia.org/resource/波の数だけ抱きしめて | 波の数だけ抱きしめて
http://ja.dbpedia.org/resource/卒業旅行_ニホンから来ました | 卒業旅行 ニホンから来ました
http://ja.dbpedia.org/resource/アマルフィ_女神の報酬 | アマルフィ 女神の報酬
http://ja.dbpedia.org/resource/踊る大捜査線_THE_MOVIE3_ヤツらを解放せよ! | 踊る大捜査線 THE MOVIE3 ヤツらを解放せよ!
http://ja.dbpedia.org/resource/きけ、わだつみの声_Last_Friends | きけ、わだつみの声 Last Friends
http://ja.dbpedia.org/resource/エンジェル_僕の歌は君の歌 | エンジェル 僕の歌は君の歌
http://ja.dbpedia.org/resource/アンダルシア_女神の報復 | アンダルシア 女神の報復
http://ja.dbpedia.org/resource/踊る大捜査線_THE_FINAL_新たなる希望 | 踊る大捜査線 THE FINAL 新たなる希望
</pre>
<br />
コードは以下を参考に、というかほぼそのまま。<br />
<a href="http://linkeddata.jp/wiki/RDF.rb">RDF.rb - LinkedData.jp Wiki</a>Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-90025293217578335412013-03-31T20:48:00.000+09:002013-04-01T20:55:32.871+09:00DBpedia日本語版:出演者を含む映画を検索織田裕二を含むページから、映画のみを抽出するSPARQLを書いてみる。<br />
<br />
<pre class="brush: sql">SELECT ?resource ?title
WHERE {
<http://ja.dbpedia.org/resource/織田裕二> dbpedia-owl:wikiPageWikiLink ?resource .
?resource rdf:type dbpedia-owl:Film .
?resource rdfs:label ?title .
}
</pre>
<br />
結果は以下のとおり。<br />
<br />
<table border="1" class="sparql"><tbody>
<tr><th>resource</th><th>title</th></tr>
<tr><td>http://ja.dbpedia.org/resource/踊る大捜査線_THE_MOVIE</td><td>"踊る大捜査線 THE MOVIE"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/踊る大捜査線_THE_MOVIE_2_レインボーブリッジを封鎖せよ!</td><td>"踊る大捜査線 THE MOVIE 2 レインボーブリッジを封鎖せよ!"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/ホワイトアウト_(小説)</td><td>"ホワイトアウト (小説)"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/湘南爆走族</td><td>"湘南爆走族"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/県庁の星</td><td>"県庁の星"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/彼女が水着にきがえたら</td><td>"彼女が水着にきがえたら"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/椿三十郎_(2007年の映画)</td><td>"椿三十郎 (2007年の映画)"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/BEST_GUY</td><td>"BEST GUY"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/将軍家光の乱心_激突</td><td>"将軍家光の乱心 激突"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/T.R.Y.</td><td>"T.R.Y."@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/就職戦線異状なし</td><td>"就職戦線異状なし"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/波の数だけ抱きしめて</td><td>"波の数だけ抱きしめて"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/卒業旅行_ニホンから来ました</td><td>"卒業旅行 ニホンから来ました"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/アマルフィ_女神の報酬</td><td>"アマルフィ 女神の報酬"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/踊る大捜査線_THE_MOVIE3_ヤツらを解放せよ!</td><td>"踊る大捜査線 THE MOVIE3 ヤツらを解放せよ!"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/きけ、わだつみの声_Last_Friends</td><td>"きけ、わだつみの声 Last Friends"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/エンジェル_僕の歌は君の歌</td><td>"エンジェル 僕の歌は君の歌"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/アンダルシア_女神の報復</td><td>"アンダルシア 女神の報復"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/踊る大捜査線_THE_FINAL_新たなる希望</td><td>"踊る大捜査線 THE FINAL 新たなる希望"@ja</td></tr>
</tbody></table>
<br />
4行目でrdf:typeをdbpedia-owl:Filmに絞り込むことで、映画のみ抽出できる。これがないと、以下のようにずらずらと必要のない結果まで出てしまう。<br />
<br />
<table border="1" class="sparql"><tbody>
<tr><th>resource</th><th>title</th></tr>
<tr><td>http://ja.dbpedia.org/resource/Category:日本の作詞家</td><td>"日本の作詞家"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/2002年</td><td>"2002年"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/日本中央競馬会</td><td>"日本中央競馬会"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/ニュースキャスター</td><td>"ニュースキャスター"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/SMAP×SMAP</td><td>"SMAP×SMAP"@ja</td></tr>
<tr><td>・・・</td><td>・・・</td></tr>
</tbody></table>
<br />
<br />Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0tag:blogger.com,1999:blog-2496014850833894063.post-23650143694355999702013-03-30T10:00:00.000+09:002013-04-01T20:55:18.781+09:00DBpedia日本語版:映画の出演者を検索<a href="http://ja.dbpedia.org/">DBpedia Japanese</a>は、Wikipediaから抽出した情報をLOD (Linked Open Data)として公開しているプロジェクト。<a href="http://ja.dbpedia.org/sparql">Endpoint</a>からSPARQLによる検索が行える。<br />
ためしに「<a href="http://ja.dbpedia.org/page/%E3%83%90%E3%82%A4%E3%82%AA%E3%83%8F%E3%82%B6%E3%83%BC%E3%83%89_(%E6%98%A0%E7%94%BB)">バイオハザード_(映画)</a>」のページから、出演者のIRIと名前を取得。<br />
<br />
<pre class="brush: sql">SELECT ?resource ?actor
WHERE {
<http://ja.dbpedia.org/resource/バイオハザード_(映画)> dbpprop-ja:出演者 ?resource .
?resource rdfs:label ?actor .
}
</pre>
結果は以下のとおり。<br />
<br />
<table border="1" class="sparql"><tbody>
<tr><th>resource</th><th>actor</th></tr>
<tr><td>http://ja.dbpedia.org/resource/ミラ・ジョヴォヴィッチ</td><td>"ミラ・ジョヴォヴィッチ"@ja</td></tr>
<tr><td>http://ja.dbpedia.org/resource/ミシェル・ロドリゲス</td><td>"ミシェル・ロドリゲス"@ja</td></tr>
</tbody></table>
<br />
<div>
参考:<a href="http://www.slideshare.net/lodjapan/linked-open-data-10164471">LODを検索する - slideshare</a></div>
Anonymoushttp://www.blogger.com/profile/00239432258795484767noreply@blogger.com0