とあるSEの手順書

個人的な技術メモです。無保証ですが参考になりましたら幸いです。

D3.jsでリソースモニターみたいなグラフの作成 version 4.0

比較的最近*1に 4.0 のメジャーバージョンアップされたみたいですね。
また、D3.js 3.0 と 4.0 は互換性がありません。

変更点は公式を参考にして、前回紹介した 3.0 グラフを書き直しました。
d3/CHANGES.md at master · d3/d3 · GitHub

対応後のグラフ

See the Pen D3_v4_LineChart by book_stone (@book_stone) on CodePen.


変更点

正直なところ 3.0 を理解していないので変更したソースも小さいため
あまり参考にならないかもしれませんが、記載させていただきます。

ざっくり大きな点といえば D3 のオブジェクト名が短くなりました。
ほとんどのオブジェクトが d3. と始まるようになったようです。

var xScale = d3.scale.linear() // v3

var xScale = d3.scaleLinear()  // v4

軸も変わりました。orientの指定せず、上下左右の軸
d3.axisTop, d3.axisRight, d3.axisBottom, d3.axisLeft が用意されています。

var yAxis = d3.svg.axis() // v3
   .scale(yScale)
    .orient("left");

var yAxis = d3.axisLeft(yScale); // v4

d3.lineオブジェクトにて、interpolateが使用できなくなり、
かわりにcurveが使えます。curveに用意されているオブジェクトを渡すことで使用できます。
用意されている種類もたくさんありますので色々試すと面白いかもしれません。
GitHub - d3/d3-shape: Graphical primitives for visualization, such as lines and areas.

var line = d3.svg.line()
    .x(function(d,i) { return xScale(i); })
    .y(function(d,i) { return yScale(d); })
    .interpolate("linear"); // v3

var line = d3.line()
    .x(function(d,i) { return xScale(i); })
    .y(function(d,i) { return yScale(d); })
    .curve(d3.curveLinear); // v4 これは直線

curveのパラメータを渡すときは下記のように。

var line = d3.line()
    .x(function(d,i) { return xScale(i); })
    .y(function(d,i) { return yScale(d); })
    .curve(d3.curveCatmullRom.alpha(0.5)); // v4

そのほか、アニメーションの個所も変更になったようです。
大幅に変更されているようですが、メソッドチェインの考え方は同じかと感じました。

*1:2016/6月末ごろに4.0にアップデートされたようです。

CodePenでD3.jsのグラフを記載してみた

CodePen

はてなブログ上でJavaScriptをゴリゴリ動かすと、
意図しない動きをする場合があるかもしれないのでCodePenを利用してみました。

CodePen - Front End Developer Playground & Code Editor in the Browser

いままでローカルでAtomChromeで試していたのですが、
CodePen上の編集も使いやすかったです。すぐ結果も出ますし、そのまま公開できますし。
よく考えたら、記事に埋め込む用のソースコードを作成していたのもナンセンスかもしれません。

CodePenの使い方はこちらを参考にしました。
【はてなブログ】CodePenをはてなに貼る方法 - のんびり猫プログラマの日常

作成したグラフ

前回のグラフと同じです。

See the Pen D3_LineChart by book_stone (@book_stone) on CodePen.

実行結果も見やすくなった気がします。
HTML、CSSおよびJavaScriptが分離されているのがいいですね。

ただペタッとコピペして使えないかもしれませんが。
次回は適当にグラフに数値を入れたりして遊んでみようと思います。

D3.jsでリソースモニターみたいなグラフの作成

前回、はてなブログで、D3.jsの動作が確認できたので、
表題のようなリソースモニターみたいなグラフができないかと作成してみました。

作成するグラフ

さっそく目標とするグラフを紹介したいと思います。
f:id:stone-book:20161020232329p:plain
データが古いものから左にずれていきますので、リソースモニターっぽく表現しようと思います。

ソースコード

基本的には、D3.jsのサンプルなどを参考にして作成しました。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<style>
/* 軸のスタイル */
.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: auto; /*アンチエイリアス処理*/
}
/* Pathのスタイル */
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}
</style>
<body>
  <div id="result">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// マージンの設定(領域)
var margin = {top: 30, right: 20, bottom: 30, left: 50},
    width = 400 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;

// 描画データ
var array = [ 2 , 0 , 3  , 4 , -1 , -2 , 5 , -3 , 1 , -5] ;

// スケールの設定 x要素としてインデックス
var xScale = d3.scale.linear()
    .domain(d3.extent(array, function(d,i) { return i; }))
    .range([0, width]);

// スケールの設定 y要素として配列の値
var yScale = d3.scale.linear()
    .domain(d3.extent(array, function(d,i) { return d; }))
    .range([height, 0]);

// X軸
var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom")
    .tickFormat(""); // 軸ラベルはなしにした

// Y軸
var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient("left");

// 線グラフのラインオブジェクト
var linestyle = "linear";
var line = d3.svg.line()
    .x(function(d,i) { return xScale(i); })
    .y(function(d,i) { return yScale(d); })
    .interpolate(linestyle);

// SVGの追加
var svg = d3.select("#result").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// グループ要素にX軸を追加
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height / 2 + ")") // 真ん中にした
    .call(xAxis);

// グループ要素にY軸を追加
svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
  .append("text")
    .attr("x", 10)
    .attr("y", -10)
    .style("text-anchor", "end")
    .text("Value");

// 実際のラインを追加
var paths = svg.append("path")
    .datum(array) // 配列をマッピング
    .attr("class", "line")
    .attr("d", line);

// データ追加し、再描画がするメソッド
function pushData(){
  // 先頭を削除
  array.shift();

  // +5から-5までの乱数発生
  var rand = Math.floor( Math.random() * 11 ) - 5 ;
  // 配列に追加
  array.push(rand);

  // path要素を削除
  // paths.remove();

  // あらたにPath追加
  line.interpolate(linestyle);

  // 追加して削除だったが、Data-Drivenっぽくない
  // paths = svg.append("path")
  //    .datum(array)
  //    .attr("class", "line")
  //    .attr("d", line);

  // データだけ入れ替る。動きは一緒。
  paths.attr("d", line);

}

// スタイルを変える(コンボのイベント)
function changeStyle(obj){
  linestyle = obj.value;
}
</script>
  </div>
</body>
<input type="button" value="Add" onclick="pushData()"/>
<select name="interpolate" onChange="changeStyle(this)" >
  <option value="linear">linear</option>
  <option value="cardinal">cardinal</option>
  <option value="step-before">step-before</option>
  <option value="step-after">step-after</option>
</select>
</html>

タイマーなどをうまく使うことで、リアルタイムにグラフが更新できるようになりそうです。
これを使ってそれっぽいグラフを次、作成したいと思います。
心電図っぽくして遊ぶのも面白いかもしれませんね。

補足

どうやら、はてなブログ上でうまく動いていなかったようなので、画像に修正しました。
変数名が衝突していたのかな。。
はてなブログ上で、JavaScriptをゴリゴリ動かすより、CodePen利用したほうがいいかもしれませんね。
CodePen - Front End Developer Playground & Code Editor in the Browser

補足2

ソースコードが Data-Drivenっぽくなかったので修正しました。
こちらの記事で動作確認できます。
stone-book.hatenablog.com

はてなブログでD3.jsの動作実験

はてなブログで、D3.jsの動作ができるか試してみました。
可視化の際に使用できればと考えております。

こちらのサイトを参考にしてみました。
はてなブログの記事内でJavascriptを書く方法 - Three.jsを使って、作ってみた

JavaScriptは以下のタグでくくっておけば使えるそうです。

<script type="text/javascript">...</script>

手順

さっそく「はてな記法」で以下を記載しました。

<div id="test" style="width:100;height:100"></div>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script type="text/javascript">
var width = 100;
var height =100;

var svg = d3.select("#test").append("svg")
 .attr("width", width)
 .attr("height", height);

svg.append("circle")
 .attr("cx",50)
 .attr("cy",50)
 .attr("r",20)
 .attr("fill","blue")
 .attr("stroke-width",3)
 .attr("stroke","black");
</script>

以下のDIVにSVG出力を試しております。

<div id="test" style="width:100;height:100"></div>

出力結果

円が表示されているようなので、使えそうです。



PythonとMeCabによるツイートの単純分析(その2)

Twitterの分析で興味を持った文献がありました。

CiNii Articles -  E-003 Extraction of Associative Relations Based on Connective Expression on Tweets

こちらの文献では「のくせに」という接続表現を検索し
「○○のくせに××」という関係から「○○」と「××」が対立する連想関係を抽出しているようです。

すこし興味を持ったので、やってみました。
環境、MeCabのインストール、Twitterのデータ収集は前回の記事と同様です。
PythonとMeCabによるツイートの単純抽出 - とあるSEの手順書

手順

  1. Twitterから「のくせに」の単語を含むツイートを取得
  2. MeCab分かち書きに変換
  3. 「のくせに」の前後の単語を抽出

スクリプト

取り急ぎ、ダウンロードしたcsvを読込、MeCabを実行して、分かち書きにして、「のくせに」の前後を
抽出する一連のスクリプトを書いてみました。

import subprocess
import pandas as pd
import codecs
import re

datas = pd.read_csv("1500ttr.csv" , header=None)
# 「のくせに」を含むもののみ抽出 (検索でなぜか「のくせに」以外が混じってた。)
datas = datas[datas[5].str.contains("のくせに")]

# CSV読込
for key, row in datas.iterrows():
    # Mecab用に出力
    fout =codecs.open("in_mecab.txt", "w" , "utf-8")
    # 5列目にツイート本文
    tw = str(row[5])
    # 英数字を消し、日本語のみに
    tw = re.sub("[^ぁ-んァ-ンー一-龠]", "", tw);
    # Mecabに食わせるファイルを出力    
    fout.writelines(tw)
    fout.close()
    
    # Mecab実行 -E でEOFを出力しない、 >> で追記 -Owakatiで分かち書き
    cmd = "\"C:\\Program Files (x86)\\MeCab\\bin\\mecab.exe\" < in_mecab.txt >> out_mecab.txt -E \"\" -Owakati"
    #cmd = "mecab < in_mecab.txt > out_mecab.txt"
    subprocess.call(cmd , shell=True)

# 出力結果を読み込む
f = codecs.open("out_mecab.txt" , "r" , "utf-8")
lines = f.readlines()

# 「○○のくせに××」の○○をsrcに××をdstに格納する
kuseni_list = pd.DataFrame(columns=["src" , "dst"])

# 1行づつ処理
for line in lines :
    # 「のくせに」まで形態素が分割されているのでとりあえず一つに
    line = line.replace("の くせ に", "のくせに")
    # 分かち書きを分割
    words = line.split(" ") 
    #「そのくせに」とかもあるので、「のくせに」だけで抽出
    if("のくせに" in words) :
        # 「のくせに」のインデックスを求め、その前後をみる
        i = words.index("のくせに")
        # インデックスを超えていないか、「のくせに改行コード」の場合スルー(jupyterの場合エスケープらいない??)
        if((i-1 >= 0) & (len(words) > i+1)) & (words[i+1] != "\r\n") :
            df = pd.DataFrame([[words[i-1], words[i+1]]], columns=["src" , "dst"])
            kuseni_list = kuseni_list.append(df , ignore_index=True)

# カウントする
pd.DataFrame(kuseni_list["src"].value_counts())
pd.DataFrame(kuseni_list["dst"].value_counts())

結果

「○○のくせに××」の「○○」の個所に含まれる単語TOP10

順位 単語 個数
1 だけ 122
2 24
3 19
4 ヒットアンドアウェー 15
5 ブス 13
6 デブ 12
7 くらい 11
8 ドラマ 9
9 8
10 8

「○○のくせに××」の「××」の個所に含まれる単語TOP10

順位 単語 個数
1 119
2 あんな 20
3 生意気 19
4 17
5 ヒットアンドアウェー 15
6 なんで 14
7 犯罪 11
8 9
9 半分 8
10 7

うーん、広告や報道などのバイアスが結構強く出てそうです。
また、リツイートによる同文が複数入っている影響もありますね。
リツイートを排除し、ユニーク文のデータ数を多くすれば、このあたりの誤差が隠れて面白い結果が
出るかもしれません。(前回の分析も・・ですね。)

参考にした論文では、CaboCha(南瓜)による構文解析も行っているみたいですね。
この辺りも、折を見て触れたいと思います。

ひとまずでした。

PythonとMeCabによるツイートの単純分析

今回は、Python形態素解析エンジンのMeCabをつかってTwitterに投稿されているツイートから
特定の単語と同時に登場する名詞を抽出し、頻出度を調べてみようと思います。

環境

Windows環境で下記を用いります。

PythonはAnacondaの利用が必要なライブラリが含まれており、jupyterが使用できておすすめです。

手順

手順は次のように非常にシンプルな構成で考えます。

  1. Twitterから特定の単語を含むツイートを取得
  2. MeCab形態素解析し、名詞のみ抽出
  3. 名詞の数をカウント

MeCabのインストール

公式サイトからダウンロードしてインストールで完了です。
辞書は、UTF-8が無難とのこと。
ただコマンドプロンプトの表面では文字化けするようです。

公式サイト
MeCab: Yet Another Part-of-Speech and Morphological Analyzer

インストールの参考にしたサイト
64bit Windows + python 2.7 + MeCab 0.996 な環境をつくる - Qiita

Windows+Python環境でMeCabを動かす際に、Visual Studioで再ビルドしたり
MeCabのライブラリをセットアップが必要です。

はやく動くものが見たい*1がために、
Pythonスクリプト内で、SubprocessコールでMeCabを実行しファイルを食わせて吐き出すことにしました。

Twitterのデータ収集

TwitterAPIで取得することができますし、収集アプリもあります。
私は下記のサイトからcsvでダウンロードしました。
UTF-8でダウンロードできるのが親切です。

1500ったー
http://membonia.com/1500ttr/

スクリプト

取り急ぎ、ダウンロードしたcsvを読込、MeCabを実行して、形態素を取得、名詞だけを抽出するまでの
一連のスクリプトを書いてみました。
pandasはCSVを読み込んだり、フィルタをかけたりとデータ操作に便利なライブラリです。

import subprocess
import pandas as pd
import codecs
import re

# CSVファイル読込
datas = pd.read_csv("1500ttr.csv" , header=None)
for key, row in datas.iterrows():
    # Mecab用に出力
    fout =codecs.open("in_mecab.txt", "w" , "utf-8")
    # 5列目にツイート本文
    tw = str(row[5])
    # 英数字を消し、日本語のみに
    tw = re.sub("[^ぁ-んァ-ンー一-龠]", "", tw);
    # Mecabに食わせるファイルを出力    
    fout.writelines(tw)
    fout.close()
    
    # Mecab実行 -E でEOFを出力しない、 >> で追記
    cmd = "\"C:\\Program Files (x86)\\MeCab\\bin\\mecab.exe\" < in_mecab.txt >> out_mecab.txt -E \"\" "
    subprocess.call(cmd , shell=True)

# 出力結果を読込
wordlist = pd.read_csv("out_mecab.txt" , header=None , delimiter="\t")
# 一般名詞だけ抽出 MeCabの形態素解析結果に品詞が記載されている
nounlist = wordlist[wordlist[1].str.contains("名詞,一般")]
# 名詞のカウントをする
pd.DataFrame(nounlist[0].value_counts(), columns=["COUNT"])

少し補足すると、MeCab実行の際につけている

-E \"\" "

このオプションは、通常、MeCabの出力結果にはEOS(end of string)が末尾に出力されます。
今回は「>>」で指定のファイルに追記し、一つの一覧にしたいため、つけました。

結果

ツイートから「美樹さやか*2」で検索した内の頻出名詞

順位 名詞 個数
1 299
2 魔法 244
3 少女 214
4 むら 211
5 あたし 116
6 110
7 それ 100
8 マギカ 99
9 杏子 81
10 ゾンビ 80

1位、5位の「私」「あたし」は「あたしって、ほんとバカ」のセリフの影響でしょうか。
2位、3位の「魔法」「少女」は、そのままですね。
4位の「むら」は最初わからなかったですが「暁美ほむら*3」の「むら」が形態素になっているようです。*4
10位の「ゾンビ」もキャラのセリフですね。

鹿目まどか*5」でもしてみましたが、「少女」「魔法」「マギカ」「フィギュア」「マギ」などで
特徴的な単語が上位にはありませんでした。
単純なので、このあたりの改善もすれば、もっと面白い抽出ができるかもしれませんね。

ひとまずでした。

*1:処理速度的には、きちんとライブラリのセットアップしたほうが良いと思います。

*2:魔法少女まどか☆マギカのキャラクター、魔法少女の一人。

*3:魔法少女まどか☆マギカのキャラクター、魔法少女の一人。

*4:こういう場合でもMeCabでチューニングできるようです。

*5:魔法少女まどか☆マギカのキャラクター、名の通り魔法少女で主人公。「まどか」で変換したら「まどか☆マギカ」が出てきて驚き。

はじめまして

このブログでは、技術メモや備忘録などを記載したいと思います。

目標とする記載内容

  • プログラミング
  • GIS
  • データの可視化

言語

などを中心に取り上げられるよう取り組みます。
ソースコードもなるべく乗せれるようにしたいです。
もちろん、ただ誤っている可能性もありますのでご注意ください。

アドバイス・改善点・ご指摘等頂けましたら幸いです。

import numpy as np
x = np.array([[1,2,3],[4,5,6],[7,8,9]])

思っているよりきれいにソースが表示されて驚きました。

ひとまずでした。