Python+R PypeRの使い方

PythonとRを同時に使うことが多いため、PypeRなるライブラリを使ってみます。
ファイル操作はPython、ネットワーク分析はRに軍配が上がると思いますが、往復するのが面倒臭いと思って導入してみました。

sudo pip install pyper

でインストール

import pyper

r=pyper.R()
print r("library(igraph)")
print r("dg<-matrix(c(0,1,0,1,0,1,0,1,1,0,0,1,0,0,0,0),nrow=4,ncol=4,byrow=TRUE)")
print r("dg")

或いは、

import pyper

r=pyper.R()
print r("""
library(igraph)
dg<-matrix(c(0,1,0,1,0,1,0,1,1,0,0,1,0,0,0,0),nrow=4,ncol=4,byrow=TRUE)
dg
""")

出力をそのままコピーすると以下のようになりました。

try({library(igraph)})

try({dg<-matrix(c(0,1,0,1,0,1,0,1,1,0,0,1,0,0,0,0),nrow=4,ncol=4,byrow=TRUE)})

try({dg})
     [,1] [,2] [,3] [,4]
[1,]    0    1    0    1
[2,]    0    1    0    1
[3,]    1    0    0    1
[4,]    0    0    0    0

pyperをimportして、r=pyper.R()でrオブジェクトを作ります。
rに引数として文字列を与えれば、その文字列そのまま、Rのターミナルへ入力したものと同じ扱いとなります。

print関数を付けるとR出力を標準出力として出せ、変数に文字列として代入することもできます。

どうもRのほうで文法ミスするとプログラムが停止しないので、一旦Rを実行できたら、そのソースコードをコピペするという使い方をしてみようと思います。


以前紹介したsqliteライブラリの扱いそっくりですね。

パイプ (コンピュータ) - Wikipedia
このpipeとpython→RをかけてPypeRということでしょうね。

逆にRからPythonを操作するrPythonライブラリもあるそうです。

Vim デザインや起動時の設定

普段はSublimeText2とVim、geditを使っています。
LinuxではSublimeText2で日本語入力ができず、geditはLaTeXで用いるものの、物足りないです。
今後はVimをより使っていこうと思っているので、設定をメモしておきます。

まずはVimのインストール

sudo apt-get install vim

また、グラフィカル版のgVimもインストールしておきます。

sudo apt-get install gvim

NeoBundleというプラグイン管理のプラグインを最初にインストールします。
git clone https://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim

set number
set ruler
set list
set listchars=tab:>-,trail:-,nbsp:%,extends:>,precedes:<,eol:<
set incsearch
set hlsearch
set nowrap
set showmatch
set whichwrap=h,l
set nowrapscan
set ignorecase
set smartcase
set hidden
set history=2000
set autoindent
set expandtab
set tabstop=2
set shiftwidth=2
set helplang=en
colorscheme desert

統計処理ソフトRとVimの連動

sudo apt-get installl tmux
cd ~/.vim/bundle
git clone git://github.com/vim-scripts/Vim-R-plugin
git clone git://github.com/vim-scripts/Screen-vim---gnu-screentmux

更に、ホームディレクトリ下に.Rprofileという名前でファイルを作る or 追記してください。

if(interactive()){
library(colorout)
library(setwidth)
library(vimcom)
}

gVimのデザイン関係は.vimrcではなく、.gvimrcで設定します。

colorscheme desert

Raspberry Pi 初期設定その1 ハード購入からOSの導入、起動までのまとめ

Raspberry Piとはマイコンの見かけをしているものの、Linuxを動かしうるれっきとしたパソコンです。
f:id:alstd:20150102201519j:plain
かわいい見た目をしていますが、Raspbianという独自のDebianLinuxを動かすことができます。
キーボードやマウスからHDMIの接続までできるので、性能の低い普通のパソコンとして扱えます。
ただの劣化版ではなく、発熱量が小さいために、サーバーとして使ったり、ブレッドボードに接続してLED制御やら温度取得などといった器用さも持っています。

創作心のくすぐられるアイテムですね。
アクアリウムをしているので、明かりの調整や餌やりの機能を実装したいと思って買いました。
勉強中の身ですが、便利な機能を見つけ次第メモしていきたいと考えています。


まず、何はともあれ、必要器具を買いましょう。
ひと通りAmazonで買ったので、リンクを貼っておきます。
下のリンクは全てアフィリエイトになっています。
賛否両論ですが、個人的にはお金が入るのは助かりますし、値段が高くなったりはしないので、是非下のリンクから買って下さい。

これに加えて、Micro-Bコネクタandroidの充電に使う端子)、キーボード、マウスが必要ですが、Micro-Bは持っている人が多く、キーボードとマウスはPCのものを代用すれば大丈夫です。
なお、後々紹介するssh接続やvnc接続を使えば、LAN内の別のPCからアクセスできるため、極論MicroSDカードとLANケーブルと電源のMicro-Bコネクタ以外はあまり使わなくなります。


まず、MicroSDカードにRaspbianを書き込みましょう。
Downloads | Raspberry Pi
サイズが大きいため、Torrentを使ったほうが圧倒的に早いと思われます。

念のためにSDカードをフォーマットしておきます。
上で紹介したAmazonのSDカードならば必要のない作業ですが。
f:id:alstd:20150102213020p:plain
Ubuntuディスクユーティリティを使います。
該当のSDカードのパーティションを全部消して、FAT32で初期化をかけます。

続いて、ダウンロードしたzipファイルを展開すると、中にimgファイルが入っていると思います。
imgファイルを右クリックしてディスクイメージライターなるものでSDカードに書き込みます。
これでRaspbianの準備は完了です。


MicroSDHDMI、キーボードを接続して、電源を繋ぐと自動的に起動します。
青背景に英語で強面な画面がでます。

  • 1 Expand Filesystemをクリックして元の画面まで戻します。
  • 2 Change User Passwordではデフォルトのパスワード"raspberry"を他のものに変えられます。
  • 3 Enable Boot to Desktop/Scratch 起動時にCUIの端末にするか、GUIにするか選べます。
  • 4 Internationalisation Options
    • I1 Change Locale ja_JP.UTF-8 UTF-8を選びましょう。通常のLinuxと同じ設定ですね。default locale for the system environmentはen_GB.UTF-8でOKです。
    • I2 Change Timezone AsiaからTokyoを選びましょう。Japanではないようです。
    • I3 Change Keyboard Layout うまく作動しない場合は自分のものに合わせましょう。
  • 5 Enable Camera カメラモジュールを買った場合は設定?
  • 6 Add to Rastrack 世界中のRaspberry Pi使いの場所が分かるとかなんとか。無視しちゃいました。。
  • 7 Overclock CPUの周波数を高くすると、寿命が短くなる代わりにパフォーマンスを上げられるそうです。用途に依りそうです。
  • 8 Advanced Options 面倒なので見ていません
  • 9 About raspi-config 面倒なので見ていません

一通り設定すれば、Finishを選択してRebootします。


ログインのIDとパスワードを要求されます。
デフォルトでは、IDがpi、パスワードがraspberryです。
先ほど設定していれば、自分の設定したものを入れてください。

以上で端末が表示されます。
Raspberry Piが起動しおわりました!
Ubuntuと同様のLinuxの端末ですので、pythonを起動したり、viを使ったりできます。


次回、Raspberry Piの日本語化やGUIなどの環境整備について説明します。

Python zipファイルの解凍時やurllib.unquote()の日本語が文字化けする問題周辺のまとめ

Windowsで圧縮したzipファイルをUbuntuで解凍するとファイル名や子ディレクトリ名に文字化けが発生することがあります。
解決方法はたくさんあるようですが、いまいち理解できないものもありました。
ほとんどの問題は、Windowsのcp932コードを変換する際に起きている模様です。
sudo権限も必要なくて一番簡単にできた(※理解できたとは言っていない)ものをメモしておきます。



こちらのサイトのPythonコードをzipfile_altとしてzipファイルのあるディレクトリに保存して下さい。

その後、同一ディレクトリで次のコードを実行すればよいです。

import zipfile_alt as zipfile

def unzip(filename, path='.', pwd=''):
    with zipfile.ZipFile(filename, 'r') as zip_file:
	try:
            zip_file.extractall(path=path, pwd=pwd)
            print 'OK'
        except:
            print 'NG'


if __name__ == "__main__":
    unzip_with_pwd(filename="test.zip", pwd="test")


urllibのほうはもっと分かりやすいです。

#coding:utf-8
import urllib
str1=urllib.quote("あいうえお")
print "str1:"+str1
str2=urllib.unquote(str1)
print "str2:"+str2
str3=urllib.quote(u"あいうえお".encode('cp932'))
print "str3:"+str3
str4=urllib.unquote(str3)
print "str4:"+str4
str5=urllib.unquote(

このときの出力は、

str1:%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A
str2:あいうえお
str3:%82%A0%82%A2%82%A4%82%A6%82%A8
str4:����������

要は、unquote()関数は、utf-8を元にしたURL文字列ならばutf-8に戻してくれますが、cp932を元にしていると、cp932に戻すために文字化けが生じます。
htmlパースしているときに起こって、気づかぬまま詰まってしまったことがありました。

こういうときは当然ながら、

print "str4:"+str4.decode('cp932').encode('utf-8')

とするだけです。

Python BeautifulSoupによるxml解析

前回、
AmazonAPI Pythonによるxmlデータの取得 - 備忘録
によって、Amazonからの商品情報をxml形式で受け取りました。

今回は、xmlSQLcsvに保存できる程度に綺麗に変換してみようと思います。


前回のコードですが、最後の行を変更しています

#coding:utf-8
import amazon import Amazon

access_key_id=""
secret_access_key=""
associate_tag=""

amazon=Amazon(access_key_id,secret_access_key,associate_tag)
xml=amazon.itemSearch("Books",Keywords=u"数学",ItemPage="1",ResponseGroup="Large")
print xml

f:id:alstd:20150102144347p:plain
変数xmlに大量の文字情報が貯められていますが、このままでは使い物にならないため、整理したり、必要な情報だけを取り出すことをxmlパース(解析)と言います。

Pythonにはhtmlパースを行うためのライブラリ、BeautifulSoupがあって、これはxmlにもある程度実用することができますし、AmazonAPI形式ならば今のところ手の届かない処理はありませんでした。


まず、BeautifulSoupのインストールは

sudo pip install beautifulsoup

です。


では、早速著者情報を抜き取り、SQLに保存してみましょう。

#coding:utf-8
from amazon import Amazon
from BeautifulSoup import BeautifulStoneSoup
import sqlite3

access_key_id="AKIAI3BTABUGQXERS6FA"
secret_acess_keys="tv0V27jJ+4ArXKtOzjQQbfHPdiibYlOS0qHsjZRU"
associate_tag="alamz-22"

con=sqlite3.connect("sample.sqlite3",isolation_level=None)
sql=u"""
create table IF NOT EXISTS Amazon_Books(
	ISBN varchar(63),
	author varchar(255),
	title varchar(255)
);
"""
con.execute(sql)

amazon = Amazon(access_key_id, secret_acess_keys,associate_tag)

xml = amazon.itemSearch("Books", Keywords=u"物理学", ItemPage="1",ResponseGroup="Large")
#print amazon.url
#print xml

#xmlにはBeautifulStoneSoup(xml)、htmlにはBeautifulSoup(html)
soup = BeautifulStoneSoup(xml)

#xmlの中からitemsを見つけ出し、itemsリストにBeautifulStoneSoupクラスとして保存
items = soup.find("items")

#何件あるかの結果は、xml内のtotalresultsタグにあり、その中身をcontents[0]で抜き出す。
print "%s件見つかりました" % soup.find("totalresults").contents[0].encode('utf-8')

#何ページあるかの結果は、xml内のtotalpagesタグにあり、その中身をcontents[0]で抜き出す。
total_pages = soup.find("totalpages").contents[0]

#xmlのitemタグ1つは、1商品の情報を囲っている。つまり、1商品の情報ごとをループ処理していく。
for item in soup.findAll("item"):
	print "\n\n------------------------------"
	ISBN=item.asin.contents[0];
	author=[]
	if item.author==None:
		author.append("None")
	else:
		for i in range(len(item.author)):
			author.append(item.author.contents[i])
	title=item.title.contents[0]

	author_str="" 
	for i in author:
		author_str+=i.encode('utf-8')+","
	author_str=author_str.rstrip(',')

	print ISBN,author_str,title

	sql='''
	insert into Amazon_Books values("%s","%s","%s");''' % (ISBN.encode('utf-8'),author_str,title.encode('utf-8'))
	print sql
	con.execute(sql)

con.close()

sample.sqlite3を確認すると、

***@***:~/AmazonAPI$ sqlite3 sample.sqlite3
SQLite version 3.8.2 2013-12-06 14:53:30
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> Select * from Amazon_Books;
4785320745|小出 昭一郎|物理学
4163757708|ウォルター ルーウィン|これが物理学だ! マサチューセッツ工科大学「感動」講義
4004200857|朝永 振一郎|物理学とは何だろうか〈上〉 (岩波新書)
4000077112|ファインマン|ファインマン物理学〈1〉力学
B009AJ8266|寺田 寅彦|物理学と感覚
4569573908|None|「量子論」を楽しむ本―ミクロの世界から宇宙まで最先端物理学が図解でわかる! (PHP文庫)
4480016007|山口 栄一|死ぬまでに学びたい5つの物理学 (筑摩選書)
4121022807|小山 慶太|入門 現代物理学 - 素粒子から宇宙までの不思議に挑む (中公新書)
B00B7UNYD2|ウォルター・ルーウィン|これが物理学だ! マサチューセッツ工科大学「感動」講義
4004200865|朝永 振一郎|物理学とは何だろうか〈下〉 (岩波新書 黄版 86)

確かに保存されています。


BeautifulSoupは他にも、サイトのHTMLから情報を抜き出すときに使われたりします。
APIに対応していなくとも無理やり情報を抜き出せるという訳です。
使いこなせると便利ですので、細々とした点まで覚えておいて損はないと思います。


参考にしたサイトです。
Beautiful Soupドキュメント — BeautifulSoup Document 0.1 ドキュメント
kondou.com - Beautiful Soup 4.2.0 Doc. 日本語訳 (2013-11-19最終更新)


SQLはいわゆるリスト内にリストを保存するような構造を持てないそうです。
例えば、authorは2人、5人、0人だったりと可変ですが、事前にデータ型を決める以上一人につき一つのセルを与えることができない、という意味です。
このときのコツとして、Pythonプログラムのauthor_strの処理のように0人ならNone、複数なら','つきで加えた一つの文にする、といった手法が取れます。
注意すべき点として、例えばauthorとしてR.P.Feynmanといった変数を保存したとき、'.'区切りならば、RさんとPさんとFeynmanさんが共著したかのような解釈となります。
区切り文字はデータとして使いそうにないものを選びましょう。

AmazonAPI Pythonによるxmlデータの取得

以前Amazonのデータを取得するAPIの登録方法を紹介しました。
Amazon Product Advertising API 登録の流れ - 備忘録


今回は実際にPythonによってデータをxml形式で取得し、xmlパースを行うことによって欲しい形式に変換する手順を追ってみましょう。

AmazonAPIに登録してIDやKeyを取得すること前提ですので、先に上の登録を終えてから読んで下さい。
また、AmazonAPIはよく仕様が変わっているようですので、2015年1月以降は細部が異なる可能性があります。


さて、xmlの解析を行う前に、まずはxmlがどういう流れで得られるのか確認します。

AmazonAPIというディレクトリを作っておきます。
そこに、以下のPythonコードをamazon.pyとして保存して下さい。
これが無いと何も実践できないため先に導入しましたが、意味を解読するためには最後まで読んだ後に戻ってきたほうがよいため、ここは作業と思って下さい。

#coding:utf-8
import urllib2
import hashlib, hmac
import base64
import time

class Amazon:
	def __init__(self, access_key, secret_access_key, associate_tag=None):
		self.amazonurl = "http://webservices.amazon.co.jp/onca/xml"
		self.proxy_host = None
		self.proxy_port = None
		self.access_key = access_key
		self.secret_access_key = secret_access_key
		self.associate_tag = associate_tag
		self.version = "2009-10-01"
		self.url = None

	def setProxy(self, host, port=8080):
		self.proxy_host = host
		self.proxy_port = port

	def setVersion(self, version):
		self.version = version

	def itemLookup(self, item_id, **options):
		params = options
		params["Operation"] = "ItemLookup"
		params["ItemId"] = item_id
		return self.sendRequest(params)

	def itemSearch(self, search_index, **options):
		params = options
		params["Operation"] = "ItemSearch"
		params["SearchIndex"] = search_index
		return self.sendRequest(params)

	def buildURL(self, params):
		params["Service"] = "AWSECommerceService"
		params["AWSAccessKeyId"] = self.access_key
		if self.associate_tag is not None:
			params["AssociateTag"] = self.associate_tag
		params["Timestamp"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
		sorted_params = sorted(params.items())

		request = []
		for p in sorted_params:
			pair = "%s=%s" % (p[0], urllib2.quote(p[1].encode("utf-8")))
			request.append(pair)

		msg = "GET\nwebservices.amazon.co.jp\n/onca/xml\n%s" % ("&".join(request))
		hmac_digest = hmac.new(self.secret_access_key, msg, hashlib.sha256).digest()
		base64_encoded = base64.b64encode(hmac_digest)
		signature = urllib2.quote(base64_encoded)

		request.append("Signature=%s" % signature)
		url = self.amazonurl + "?" + "&".join(request)

		return url

	def sendRequest(self, params):
		self.url = self.buildURL(params)
		if self.proxy_host:
			proxy_handler = urllib2.ProxyHandler({"http":"http://%s:%s/" % (self.proxy_host, self.proxy_port)})
			opener = urllib2.build_opener(proxy_handler)
		else:
			opener = urllib2.build_opener()
		return opener.open(self.url).read()

こちらのサイトから引用させて頂きました。


続いて、先ほどのソースコードと同じAmazonAPIディレクトリにamazon_search.pyとして次のファイルを置きます。

#coding:utf-8
import amazon import Amazon

access_key_id=""
secret_access_key=""
associate_tag=""

amazon=Amazon(access_key_id,secret_access_key,associate_tag)
xml=amazon.itemSearch("Books",Keywords=u"数学",ItemPage="1",ResponseGroup="Large")
print amazon.url

access_key_id、secret_access_key、associate_tagには自分のものを代入してください。
実行すると、print amazon.urlの出力としてURLが得られるはずなので、それをブラウザで見てみましょう。
f:id:alstd:20150102023029p:plain
xmlが確かに得られています。

amazon_search.py内の

xml=amazon.itemSearch("Books",Keywords=u"数学",ItemPage="1",ResponseGroup="Large")

という記述通り、数学に関する本を1検索分(=10冊分)、詳細なデータ(=Large)で得られています。


AmazonとPC間の情報のやりとりはたったこれだけで終わりです。

もちろん、検索の関数としてitemSearch以外にもありますし、オプションもResponseGroupの属性として山ほどあります。
ただし、これらは固有名詞的なものなので覚えてもあまり意味がないですし、Amazon公式マニュアルを参考にしましょう。


その後はxmlパースに移ります。
区切りがよいので次回に回します。
Amazonクラスに関する説明も、仕様が変わったり、他のAPIにも応用する上では必要なので、いずれ説明する予定です。

SQLite インストールと基本操作

大きなデータを扱う機会が増えて、csvでは重かったり、手の届かない処理をしたいと思ってデータベースSQLを触ったことがあります。
SQLcsvなどに比べて軽く、準備されている関数(SQL文)をプログラムから投げることでソートや検索のプログラムを組まなくとも結果を返してくれるなどの利点があります。
多くのサイトや企業でも採用されているようです。
一方で、多くのプログラミング言語が対応しているものの、SQLのライブラリを持っていなければ、扱うのは面倒臭いかもしれません。
その場合、SQLでとりあえずなんでも保存して、必要な部分だけcsvとして用いる、という手法が便利ですね。
PythonによるSQLの扱い方も最後に紹介します。


今回はSQLの導入と基本的な構成・操作を紹介したいと思います。(Ubuntu14.04)
まずインストールは端末で、

sudo apt-get install sqlite3

で出来ます。

続いて起動です。

sqlite3 sample.sqlite3

として、sample.sqlite3を作ってみましょう。

create table book(author varchar(50),title varchar(50),price int);

と入力してみて下さい。
ここまでで、sample.sqlite3ファイルの中に、bookというテーブルが作成されました。
bookというテーブルはauthor、priceという変数を持っていて、その変数に文字列が保存されるという仕組みです。

ここまでで、データを入れる型を作る作業ができました。
実際にデータを入れてみましょう。

insert into book values ("Richard Phillips Feynman","The Feynman Lectures on Physics",3600);

これで、Richard Phillips Feynman著、The Feynman Lectures on Physic、3600円というデータが得られた訳です。

入っているデータを確認するには、以下のように打ち込みます。

select * from book;

SQLの各種文法や関数は僕自身学んでいる途中ということで、他のサイトに任せたいと思います。


SQL文をプログラミング言語から投げて、データを保存する、といったことができます。
Pythonでの使い方を紹介します。
Pythonによってネット上からデータを取得したり、或いは実験データの数値を算出して、それをSQLに保存するといった芸当が可能になります。
この連動自体は極めて簡単ですので、SQLの文法を学ぶより先に読んでもよいと思います。

#coding:utf-8
import sqlite3

#sqlite3のデータベースに接続
con = sqlite3.connect("sample.sqlite3") 

#SQL文の作成
sql=u"""
create table book(
	author varchar(50),
	title varchar(50),
	price int
);
"""

#sqlへ投げかける
con.execute(sql)

#接続の解除
con.close()

SQL文を作って、それをcon.execute(sql)によって投げかけるだけで終わりです。


データを読む操作の例として、データが登録されているか確認する関数を作ってみましょう。
まだ紹介していないSELECT文を使っていますので、読めばわかると思いますが、詳しくは調べてみて下さい。

def is_exist_author(target):
	sql = 'SELECT author FROM book author ="' + target + '"'
	cur = con.execute(sql)
	if len(cur.fetchall()):
		return True
	else:
		return False

bookテーブルのauthor属性の中に、targetというデータが含まれていた場合Trueを返し、存在しない場合はFalseを返します。
curはSQLによる出力を保存していて、fetchall()メソッドの結果が0より大きければTrue(データあり)ですね。
これを使えばデータの重複を確認することなどもできます。


以前、Amazonの書籍データを可視化した際にも実はSQLデータベースを使っていました。
そのときは、
1,PythonによってAmazonAPIからデータ取得、著者やタイトルなどをSQL文に書き直す。
2,SQLにデータを貯めこむ。
3,PythonによってSQLcsv形式に変換する。
4,Cytoscape、R、NetworkX(Python)によって可視化させる。
という流れを取りました。