GIG

赴くままに技術を。

APIで取得したjsonが文字化けする

備忘録としてメモ。 やりたいことは、REST API提供されているデータを取得して、保存することです。

また使用しているpythonの環境は、以下。

 python --version
Python 3.4.3 :: Anaconda 2.2.0 (x86_64)

使用するデータは、e-StatのAPIから取得します。 APIを使用するに歳しては、まずユーザ登録をして、アプリケーションIDを発行しなくてはなりません。

www.e-stat.go.jp

提供されている機能としては5種類あります。 主に使いそうなものとしては、下記の2点になるかと思います。

  1. 使いたいデータの政府統計コードを使って、「統計表情報取得」機能から利用したい統計表IDを取得
  2. 「統計データ取得」機能からデータを取得

今回は、2点目の機能を利用。 平成22年国税調査 速報集計(0003033021)を例として、取得してみました。

#! /usr/bin/env python
#-*- coding: utf-8 -*-

import urllib.request, urllib.parse
import json, sys

def getEStatData():
    jsonUrl = "http://api.e-stat.go.jp/rest/2.0/app/json"
    apiKey = "(YOUR API KEY)"
    statId = "0003033021" # 平成22年国税調査 速報集計

    statsDataUrl = "%s/getStatsData?appId=%s&statsDataId=%s"
    url = (statsDataUrl % (jsonUrl, apiKey, statId))
    print(url)
    f = urllib.request.urlopen(url)
    jsonData = json.loads(f.read())
    print (jsonData)

    file = open('StatsData.json', 'w')
    json.dump(jsonData, file, sort_keys=True, indent=4)
    file.close()

if __name__ == '__main__':
    sys.exit(getEStatData())

urlib.request.urlopenがbyte型を返すことに注意(参考; http://docs.python.jp/3/library/urllib.request.html)

TypeError: the JSON object must be str, not 'bytes'

下記のようにutf-8にデコードすると日本語のままデータが取得できますが、このようにデコードした場合でもERROR_MSG":"\u6B63\u5E38\u306B\u7D42\u4E86\u3057\u307E\u3057\u305F\u3002"Unicodeエスケープされてしまう場合があったのですが、そんなときにはunicode-escapeを指定することで、回避していました。(正直、違いがわからない)。

    jsonData = json.loads(f.read().decode('utf-8'))
    print (jsonData)

一方で、出力したjsonファイルの方は、Unicodeエスケープされてしまいます。 これはjson.dumpsの引数であるensure_asciiがデフォルトでTrueになっており、入ってくるデータをエスケープする仕様になっていることに起因します。

従って、それをFalseにすることで、ファイルに書き出したときも日本語が保つことができます。

    file = open('StatsData.json', 'w')
    json.dump(jsonData, file, sort_keys=True, indent=4, ensure_ascii=False)
    file.close()

if __name__ == '__main__':
    sys.exit(getEStatData())

LeafletとCrossletを組み合わせたCrossLetで日本の人口統計データを表示する

CrossletというLeafletの地図表示上と、Crossfilterを連動させたJavascriptライブラリを用いて、各都道府県の国籍別に人口データを表示してみました。

ライブラリはLeafletがCloudMadeのAPIを使う仕様のままになっており、 今のLeafletのようにOpen Street Mapを使うようにライブラリの修正が必要ですが、 今回はそのまま利用しました。

github.com

ちなみにこのCrossletのことをRライブラリのrMapsではじめて知りました。 rMapsは、rChartsやSlidifyと同じ方で、Rのビジュアライゼーションの可能性を広げられてます。

データ

  • 日本topojsonデータ

D3.jsが流行ってからShapefileからTopojsonを作る解説が巷にいくつもでているので、割愛。 Topojson形式のデータを使用していますが、Geojsonもサポートされているそうです。

Crosslet also supports TopoJSON, a GeoJSON extension that allows to present geometry in a highly compact way.

人口統計データは、e-Statという政府統計データのポータルサイトからダウンロード致しました。項目は「外国人」にある41項目目です。そのままCSVをダウンロードするのではなく、[DB]から都道府県だけにデータをそぎ落としてからCSV形式でダウンロードしました。

その他にもデータにした修正 * 文字コードの修正 (Shift-JISからUTF-8) * ヘッダーの修正 * 文字列の数字を数値データ

"1234"みないなデータであれば、pandas.DataFrame.as_typeで変換できますが、"1,234"とカンマが入っていたために詰まった..。 データ少なかったから手で修正してしまったけど、課題として残しておく。

Crosslet

CSS

LeafletとCrossletのCSSを読み込みます。

<link rel="stylesheet" href="styles/crosslet-min.css" />
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
    <style>
      html{
        height: 100%;
      }

      body{
        margin: 0px;
        padding: 0px;
        height: 100%;
      }

      #map{
        height: 100%;
      }
    </style>

Javascript

Backboneを採用しているとのこと。ほー。

<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/2.10.0/d3.v2.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
<script src="scripts/lib/crosslet.js"></script>

Crossletの描画設定

Crossletは、設定をJson形式で記載してCrossletのインスタンスを生成する際に引数で与えます。 このJsonの中身は以下のようになっています。

var config = {
  map : {
      (LeafletとオーバーレイさせるGeojsonまたはTopojsonの設定)
  },
  data : {
      (読み込むデータのうち、先に読み込んだGeojsonまたはTopojsonの各地域と結ぶための列名を指定)
  },
  dimensions : {
      (地図と関連させる棒チャートの設定。データの読み込む列やフォーマット、カラースケールを設定)
  },
  defaults: {
      (棒チャートのパネルの表示を設定)
  }
};

new crosslet.MapView($("#map"),config);

あとはhtmlのmap要素に表示されます。

  <div id="map"></div>
map

CloudMadeのAPIはもう利用できないので、leafletの設定はほっておきます。TopoJsonはgeo配下で設定しています。 name_fieldは表示名として使用されるもので、TopoJsonの中のフィールド名を指定します。id_fieldは後ほど読み込むデータと行を一致させるための一意になっているフィールド名Topojsonから選びます。 topo_objectはTopojsonの時に必須の項目で、Topojsonの中から"objects"のすぐ直下のフィールド名を拾います。

  map: {
    leaflet: {
      key: (CloudMade発行のAPI Key,
      styleId: 64657,
      attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://cloudmade.com">CloudMade</a>'
    },
    view: {
      center: [39, 135],
      zoom: 6
    },
    geo: {
      url: "data/crosslet/japan.topo.json",
      name_field: "name_local",
      id_field: "name",
      topo_object: "japan"
    }
  },
data

versionは特につかっていないようなので、データの列名で先ほど設定したid_fieldと一致させる列名を指定します。

data: {
    version: "1.0",
    id_field: "id"
  },
dimension

ほぼ同じ設定なので、一例のみ。japaneseとあるフィールド名はこの後のdefaultで指定するので一意に設定します。 titleは各パネルに表示されるタイトル、dataSetは読み込むデータファイル, fieldはそのうちこのパネルで読み込むデータ列の列名, さらに読み込むデータファイルの形式はデフォルトTSVですが、methodd3.csvとするとCSV形式を読むことができます。colorscale には、d3.scale.linear()を渡してカラースケールを設定することができます。最後のformatは、別に定義したvar inp = function() { return d3.format(",.0f") };を渡して、千の位にカンマを入れるフォーマットにしています。またshortも表示される表示データのフォーマットを指定するものです。

dimensions: {
    japanese: {
      title: "Japanese population",
      data: {
        dataSet: "data/crosslet/foreign_census.csv",
        field: "日本人",
        method: d3.csv,
        colorscale: d3.scale.linear().domain([0,5,20]).range(["green","yellow","red"]).interpolate(d3.cie.interpolateLab)
      },
      format:{
        short: inp,
      },
    },
  },
defalt

最後のdefaultは、パネルの並びとアクティブなパネルの設定を設定します。 opacityはパネルの透過度かとも思ったんですが、変えても変化がない...。 これはソースコード読まないとわからないですね。

  defaults: {
    opacity: 0.7,
    order: ["korean", "chinese", "philipino", "thai", "indonesian", "vietnamese", "english", "american", "brazilian", "peruvian", "others", "japanese"],
    active: "korean"
  },

消えた兵庫県

表示してみたら、兵庫が消えた\(^o^)/ というか静岡もnull !

f:id:hermesian:20150329200753p:plain

原因

Topojsonを見てみたら、Hyōgoとなっているoに長音記号がついてる...。 静岡もname_localがnullになっていたので修正して、無事表示されました。

f:id:hermesian:20150329200807p:plain

TOEICのスコアに一喜一憂する

TOEICを1,000円で受けられる機会が社内で年数回あります。 まぁ受けて損はないかと惰性で受けてますが、Readingあがらんね。 TOEICで英語の能力は測りきれないとは思うものの、取れないとそれはそれで悔しい。

受験日 Listening Reading
2015.02 445 320
2014.08 410 375
2012.02 390 365
2011.08 365 325
2010.04 355 320

原因は文法と単語をあまり知らないことな感覚はあるので、 来年度中にはなんとか800越えたいなぁ

北小金-流山-利根運河

流山に移り住んで4ヶ月くらいになります。 流山といってもほぼ松戸市に接するようなところに住んでいるのですが、ここから野田市との境までポタリングしてきました。

利根運河

流山に転入してきたとき、利根運河の写真が載っていた冊子などを頂きましたが、 まさかここだとは思いませんでした(名前も行って初めて知った)。

運河駅は理科大の最寄駅なんですね。 勉学に集中できそう^^;

利根運河。あいにくの天気ですが雨は降らず走りやすい天候。 f:id:hermesian:20150315100249j:plain

なくなりつつある原風景

流山は「都心から一番近い森のまち」を掲げてますが、TX沿線の開発に伴う里山の切り崩しを見ていると近い将来そうなくなるのかなぁ。 画一化された分譲住宅の背後に広がるおおたかの森を見てると、そう思わざるを得ない。

手前に広がる里山風景と、奥に広がる開発中のセントラルパーク f:id:hermesian:20150314141642j:plain

IPythonで最初からimportさせておく設定

IPythonを使っていると最初からimportしていてほしいなと思うときがしばしば。 前回行ったIPythonプロファイルで設定できるようなので、以下やってみる。

~/.ipython/profile_default/配下にあるプロファイルを編集しても良いのですが、 後で見直したいときもあるかなと思い、まずはIPythonプロファイルを作成するところから。

$ ipython profile create basic_settings

すると~/.ipython/profile_basic_settings配下にプロファイルが作られます。 この中のipython_config.pyにimportさせたいライブラリを加筆します。

# lines of code to run at IPython startup.
c.InteractiveShellApp.exec_lines = [
        "import numpy as np",
        "import pandas as pd",
        "import matplotlib.pyplot as plt",
        "%matplotlib inline"
]

このプロファイルを使ってIPythonを起動します。

ipython notebook --profile=basic_settings

これで明示的にimportを書くことなくライブラリを利用できます。

「Pythonによるデータ分析入門」を読む準備をする

今までJavaPerlをその場しのぎとして業務をしてきましたが、昨今の流れもあってPythonを使い始めました。

Amazonやアキバのヨドバシを眺めてみましたが、Pythonってあまり書籍がでていない...。その一方、RubyなんかはWebシステムの構築で使われる頻度が増えて、本があふれんばかり。

Rubyもいつかは身に付けたいけど、データの前処理用途で使おうと思うと、多次元配列に対応しているかや、科学計算ライブラリとかも気になる点です。 あるみにはあるにはあるみたいですが(いつか試してみよう...)。

SciRuby

Pythonによるデータ分析入門」から始める

そんなわけで、出だしに手をつけたのが「Pythonによるデータ分析入門」です。 著者のWes McKinney氏は、クオンツとしての経験をもとにデータ処理ライブラリのpandasを作成されたことでも知られています。

内容としては、NumPy, pandas, matplotlib, IPython, Scipyといったデータ分析で利用されるライブラリをハンズオン形式で解説しています。ところどころ事例紹介があり、後々参考になりそうです。

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

読むための環境を整備する

IT関連の書籍にありがちですが、手を動かさないと頭に入ってこないので、環境を構築します。 備忘録代わりに日記にしたためておくとしよう。

手元のPCのスペック;

Macにがっつり構築しようとするとバージョンアップ時やに困りそうなので、 仮想環境として構築します。

VMの準備

手始めに、Oracle VM VirtualBox, Vagrantをインストールします。

1. Boxのダウンロード

利用したい仮想マシンをダウンロードしてきます。 社内の環境でも使っていることから、Redhat系のディストリビューションということで、CentOSを入れます。 ( centos70仮想マシンの識別名なので、適宜変更してください。)

$ vagrant box add centos70 https://dl.dropboxusercontent.com/s/srw2tqh58507wik/CentOS7.box

Boxはいくつか提供しているところがあるみたいですね(前者しか知りませんでした...)。

2. 仮想マシンの作成

仮想マシンを作成すると設定ファイル(Vagrantfile)が生成されるため、適切なディレクトリを作成してそこで下記のコマンドを実行します。

$ vagrant cenos70

ログがつらつらと吐き出され、仮想マシンが立ち上がりました。 下記コマンドで入れます。

$ vagrant ssh

ログインユーザはvagrantとなっています。 またrootユーザの初期パスワードは、vagrantです。

また今回は自宅なので、特に必要はないのですが、会社などでproxyの設定が必要な方は、 後々のパッケージのインストールに先立ち、vagrant-proxyconfを入れておきましょう。

$ vagrant plugin install vagrant-proxyconf

Vagrantfileに下記の行を追加します。

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

...(以下の行を追記)
     config.proxy.http = "http://(ユーザID):(パスワード)@(Proxyのドメイン名):(Proxyのポート)"
     config.proxy.https = "http://(ユーザID):(パスワード)@(Proxyのドメイン名):(Proxyのポート)"
     config.proxy.no_proxy = "localhost,127.0.0.1"
...(以上の行を追記)

end

仮想マシンを再起動します。

$ vagrant reload 
CentOSのセットアップ

1. 基本セットアップ

開発環境を一式入れておきましょう。

$ sudo yum groupinstall "Development tools"

さらに、pyenvの利用に際して以下を追加します(参考: Common build problems · yyuu/pyenv Wiki · GitHub)

$ sudo yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel

あと、matplotlibのインストールする際に必要なものとして、

$ sudo yum install python-devel libpng-devel freetype-devel

必要に応じてproxyの設定をします。

# sudo vi /etc/profile

...(以下の行を追記)
PROXY=http://(ユーザID):(パスワード)@(Proxyのドメイン名):(Proxyのポート)
export http_proxy=$PROXY
export https_proxy=$PROXY
...(以上の行を追記)

あと、F/Wも切っておきたいところです(甘えですが)。

# systemctl stop firewalld
# systemctl disable firewalld

2. Pythonのインストール

2.X系、3.X系とありますが、何をしたいかで変更したい場合もあるかと思いますので、インストールバージョンを管理できるpyenvを利用します(以下では、XXXenv系をまとめて管理するanyenvを利用)。

$ git clone https://github.com/riywo/anyenv ~/.anyenv
$ echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(anyenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l

pyenvをインストールします。

$ anyenv install pyenv
$ exec $SHELL -l
$ anyenv versions      # インストールされたか確認

それではpythonをインストールしましょう。 まずはどれをインストールするかリストから選びます。

$ pyenv install --list
Available versions:
  2.1.3
  2.2.3
  2.3.7
  2.4
  2.4.1
  2.4.2
  2.4.3
...(以下、省略)

今回は、3.4.2をインストールします。 また、今後バージョンを使い分けることを想定して、~/dev/python配下のみ 3.4.2を使うことにします。

$ pyenv install 3.4.2
$ mkdir -p ~/dev/python
$ cd ~/dev/python
$ python --version
Python 2.7.8
$ pyenv local 3.4.2
$ python --version
Python 3.4.2
ライブラリのインストール

pythonのライブラリを管理するpipを使ってインストールしていきます。 順番は、

  1. Numpy
  2. Scipy <- Numpyが先に必要
  3. Pandas
  4. matplotlib
  5. IPython

1. Numpyのインストール

$ pip install numpy

2. Scipyのインストール

  • 科学計算ライブラリ
  • Numpyライブラリに依存
  • 必要なBLASLAPACKといったライブラリを有償のものを使うなどカスタムインストールすることも

インストール結構時間かかるな...

$ pip install scipy

3. Pandasのインストール

  • RのあのDataFrameが利用可能
  • group byやmergeなどデータの取り回し機能ライブラリ
$ pip install pandas

4. matplotlibのインストール

  • 2Dのチャート描画ライブラリ
$ pip install matplotlib

5. IPythonのインストール

$ pip install “ipython[notebook]"

外部からブラウザでアクセスできるようにします。 デフォルトはいじらず、プロファイルmyprofを作り、その設定に修正を加えます。 ポートの変更もこのプロファイルで変更できます。

$ ipython profile create myprof
$ vi ~/.ipython/profile_myprof/ipython_config.py

...(以下の行を追記)
c.NotebookApp.ip = u'*'
...(以上の行を追記)
ようやくスタートライン

これでようやく読み始められます。

  • --no-browserオプションは起動時にブラウザを自動的に起動しないため
  • --matplotlib inlineオプションはmatplotlibをnotebook上で描画するため
 ipython3 notebook --profile=myprof --no-browser --matplotlib inline &

あと使用されているデータは、pydata/pydata-book · GitHubからcloneしてきましょう。 ipythonを起動(上記のコマンドを実行した)ディレクトリに降りて、下記のコマンドを入力します。

$ git clone https://github.com/pydata/pydata-book

本の中では~/ch0X/となっている点を~/pydata-book/ch0X/と読み替えればいけるかと。 最後にhttp://localhost:8888から始めるとしましょう。

iPhone 4sからiPhone 6に変えてみた

iPhone 5が出てからもがんとしてiPhone 4s(これだけで3代目)を手放しませんでした。 個人的な信条からなのですが、画面の大きさにこだわるAppleなんて見たくなかったし、OSが更新されていくので、機能面で購入する動機がないなーとぼんやり思ってました。

替えやがった

そんなある日、2015/1月中に下取りしたらiPhone 6(16GB)の機種代がカバーされると知って、うっかり帰り道アキバヨドバシへっ (信条なんてホコリなみの軽さでふっとんだ)

4.7inchというほぼ本体を握っているような薄さ。 取り付けが若干苦労しましたが、満足してます。 外し方はそのときにでも考えるか(汗

  • フィルム: (商品名どわすれ) ガラスフィルム

ケースにも付属のフィルムが付いてますが、前々からガラスフィルムを使って見たかったので、購入してみました(赤いハイヒールで画面を踏んでいるパッケージのやつ)。

ところが... iPhone 6ようにもかかわらず、画面の方がややはみ出している--; 画面のさわり心地は良いのですが、いまいち。

結局よかったのか?

やはり通勤中の片手使いには決して使いやすいものではないなと思います。 その分、電子書籍の見易さは、画面の大きさと綺麗さで段違いに良い! そういう意味だとタブレットの2台持ちはしなくなったなー