R勉強メモ(基礎編)
ISITのRを用いたデータ分析基礎を受講したのでメモ
Rとは?
Rの概要
マルチプラットフォーム (Win/Lin/OSXで動作)
複雑なデータ型に対する処理が勘弁
統計関数が充実
Rの基礎
Rを用いたデータ分析の基礎
Rのオブジェクト
変数、データ、関数など 名前を付ける=付値
[オブジェクト名] <- [値] でオブジェクトに値を代入する。
> X <- 1
Rの作業ディレクトリ
以下で確認可能 作業ディレクトリ配下のデータファイルを読み込む
> getwd() [1] "/hogehoge"
作業ディレクトリを変更するとき
> setwd("/work")
helpと終了
> help(関数名) > q() > quit()
データタイプとデータ構造
型+構造でデータを表現
データタイプ
- logical 2値
- integer 整数
- double 実数
- complex 複素数
- character 文字列(演算はできない)
データタイプの確認方法
> typeof(obj)
Rはデータタイプを自動的に決定する。
数値は明示しない限りdouble型 タイプが混じった演算はより大きい型になる
データ構造
スカラ
単一のデータを持つ 定数、変数
ベクタ
同一データタイプを一次元で列挙したもの
要素アクセス ベクタ[要素番号] ベクタ[c(要素番号, 要素番号...)]
数値ベクタ
> 3:6 [1] 3 4 5 6
seq関数を使って、初項、末項、公差を指定してベクタを生成する。
> seq(4, 8, by=2) [1] 4 6 8
rep関数を使って、xをm回繰り返して並べたベクタを生成
> rep(6:7, times=2) [1] 6 7 6 7
c関数を使って、任意のベクタを生成
> c(1,2,1,1) v1 <- 1:5
ベクタ同士を連結
> c(v1, 6:10) 1 2 3 4 ... 10
scan関数を使って、ファイルからベクタを読み込み
scan("ファイル名", skip=s, nlines=n) skipは先頭s行をスキップすることを示している。 nlinesはn行のデータを読み込むことを示している。
rnorm(n, mean=m, sd=d)を使ってガウス分布に従った、乱数列を得る 項数n, 平均m, 標準偏差d
runif(n, max=mx, min=mn)を使って一様分布に従った、乱数列を得る 項数n, 最大値max, 最小値min
その他もあり
行列
列と行に要素を並べたデータ型
matrix(v1, nrow=n1, ncol=n2, byrow={TRUE|FALSE}) ベクタv1からn1行n2列の行列を生成 byrowで列優先か行優先かきまる。(元のベクタが列に準ずるか行に順ずるか)
n1n2がv1の要素数と一致 => v1の全要素が行列化 n1n2がv1の要素数より大きい => v1の要素を繰り返し n1n2がv1の要素数より小さい => v1の要素をn1n2までの要素で生成
元のベクタのもっとも表現力の高いデータタイプになる ncolを省略した場合は自動で決定。(割り切れない場合は上のルールでデータ埋められる) byrowはデフォルトTRUE
要素取り出し
mat[3] => 3行目1列のデータをスカラ値として返す mat[1,1] => 1行1列のデータをスカラ値として返す mat[1,] => 1行目のすべてをベクタとして返す mat[,1] => 1列目のすべてをベクタとして返す mat[c(1,3),] => 1,3行目を抜き出した新しい行列を返す
リスト
異なるタイプのオブジェクトを一次元に並べて管理するデータ型
list(n1=o1, n2=o2,...) キーn1にオブジェクトo1を格納 キーn2にオブジェクト02を格納 したリストを生成する。
例
> testList <- list(name="test", number=20) > testList $name [1] "test" $number [1] 20
str(<listオブジェクト>) でリストの構造を表示する
> str(testList) List of 2 $ name : chr "test" $ number: num 20
<リストオブジェクト>$<キーの名前> <リストオブジェクト>2 <リストオブジェクト>"<キーの名前>" で要素アクセスする
また、 <リストオブジェクト>[数値範囲] <リストオブジェクト>["<キーの名前>"] とすると リスト型で返却される
> testList$number [1] 20
データフレーム
リストの一種 表を表現したもの
1要素 (=行) は異なるタイプのオブジェクトの列となっている 1変量 (=列) はデータフレーム中ですべて同じ要素数となっている必要がある。
data.frame()によってデータフレームを生成する。
read.csv("<ファイル名>", header={TURE(default)|FALSE}, sep=","(default)) によって、CSVファイルを読出してデータフレームに付値する
ベクタの羅列からデータフレームを生成することも可能 ※各ベクタの要素数は同じである必要がある
str(<データフレームオブジェクト>)で構造を確認可能
> df<-data.frame() > df<-read.csv("example-readtable.csv") > df Name Japanese Math English Chemistry Geography 1 AAAA 55 70 80 45 60 2 BBBB 90 50 90 40 80 3 CCCC 60 65 65 60 60 4 DDDD 80 85 85 80 70 5 EEEE 95 40 100 70 50 > str(df) 'data.frame': 5 obs. of 6 variables: $ Name : Factor w/ 5 levels "AAAA","BBBB",..: 1 2 3 4 5 $ Japanese : int 55 90 60 80 95 $ Math : int 70 50 65 85 40 $ English : int 80 90 65 85 100 $ Chemistry: int 45 40 60 80 70 $ Geography: int 60 80 60 70 50
要素アクセス
一重の大かっこ <データフレームオブジェクト>[1] <データフレームオブジェクト>["<変量名>"]
=> ある一変量の全データがデータフレーム型で返却される
二重の大かっこ [] <データフレームオブジェクト>1 <データフレームオブジェクト>"<変量名>"
=> ある一変量の全データがベクタ型で返却される
> df[2] Japanese 1 55 2 90 3 60 4 80 5 95 > df[[2]] [1] 55 90 60 80 95
<データフレームオブジェクト>[<行番号>, <列番号|変量名>]
=> ある一要素、または部分データフレーム
※ある行すべてを抜き出す場合列番号は省略
> df[1,1] [1] AAAA Levels: AAAA BBBB CCCC DDDD EEEE > df[1,1:2] Name Japanese 1 AAAA 55
データフレームからのデータ抽出
subset(<データフレーム>, subset=抽出条件, select=抽出変量)関数で、条件に従ったデータを抜き出し
> subset(df, subset=Japanese>70) Name Japanese Math English Chemistry Geography 2 BBBB 90 50 90 40 80 4 DDDD 80 85 85 80 70 5 EEEE 95 40 100 70 50 > subset(df, subset=Japanese>70, select = c(Japanese,English)) Japanese English 2 90 90 4 80 85 5 95 100
データフレームの結合
merge(x, y) x,y データフレームの結合 共通の変量で同じ要素を持つものはマージされる
edit(df) df データフレーム エディタが表示され、データを編集できる ※返り値に編集されたデータフレームが返却される。
因子(Factor)
文字列などは因子型として管理される 文字列ベクタに現れる要素に水準値をつけ、その水準値でデータを表現する。
factor(v) vはベクタ
水準は辞書順に値が与えられる。
水準値を自分で与えることもできる。
factor(v, levels=lv, ordered={TRUE|FALSE}) lv 水準ベクタ ※lvに含まれていない、要素がvにあるとエラー
ordered 順序関係を規定するか?(TRUEの場合、水準ベクタの要素順に大小関係が規定されている) ※四則演算には意味がないのでエラー
演算
四則演算
スカラとベクタの四則演算
ベクタのすべての要素にスカラ値との四則演算結果となる
対応する要素同士の演算となる
論理値ベクタが返る
長い方に合わせて、短い方を繰り返す
ベクタの演算
行列の演算
四則演算 各要素の演算 行列演算も可能
データの性質
質的データ
四則演算ができないデータ
名義尺度
便宜的に、数値を割り振ったデータ
一致/不一致 比較、計数
順序尺度
順序に意味がる名義尺度
大小比較
量的データ
間隔尺度
順序が等間隔で定義される順序尺度
加減算が可能
比例尺度
原点が設定されている間隔尺度
剰余算が可能
DBGENを使って、PostgreSQLにTPC-H測定用データを格納
DBGEM導入
1. DBGENのダウンロード、展開
TPC-Hのサイトからダウンロードします。
$ wget http://www.tpc.org/tpch/spec/tpch_2_17_0.zip $ unzip tpch_2_17_0.zip
2. DBGENのインストール
makefile.suiteを環境に合わせて書き換えます。
$ cd tpch_2_17_0/dbgen $ vi makefile.suite
今回は、
で試しています。
以下の部分だけ変更しました。
CC = gcc DATABASE= ORACLE MACHINE = LINUX WORKLOAD = TPCH LDFLAGS = -O3
そして、コンパイル。
$ make -f makefile.suite
dbgenとqgenという実行ファイルが生成されます。
3. テストデータ生成
$ ./dbgen -s 10
-s オプションで生成されるデータのスケールを決めます。 上記で10GBのテストデータが生成されます。 以下のファイルが生成されていれば成功だと思います。
- customer.tbl
- lineitem.tbl
- nation.tbl
- orders.tbl
- part.tbl
- partsupp.tbl
- region.tbl
- supplier.tbl
PostgreSQLにテストデータをロード
データベース作成とかは省略。 testdbというデータベースを作成したものとします。
1. テーブルを作成
dbgen ディレクトリの配下に、dll文が用意されているのでそれを利用します。
$ psql -d testdb -f dss.ddl
これは特に変更しなくても使えました。
2. データをロード
COPY文を使って"*.tbl"をロードします。 が、そのままでは失敗します。。。
DBGENは、テストデータの行末にデリミタを入れるのですが
1|AMERICA|hs use ironic, even requests. s|
PostgreSQLは最後のデリミタの右側にデータがあると怒ります。。。
testdb=# copy region from '/home/postgres/tpch_data/region.tbl' with delimiter '|'; ERROR: extra data after last expected column CONTEXT: COPY region, line 1: "0|AFRICA|lar deposits. blithely final packages cajole. regular waters are final requests. regular ac..."
この解決方法ですが色々調べた結果、 sedコマンドからのパイプラインとCOPY文の標準入力からのロード機能を使うのがスマートで良さそうです。
$ sed -e 's/|$//' supplier.tbl | psql -d testdb -c "copy supplier from STDIN ( delimiter '|');"
ちなみにデフォルトの設定だと、チェックポイントの間隔が身近すぎるとWARNINGを出されるので設定を変えておくと良いかもしれません。
3. 制約の追加
dss.riを使ってインデックスを追加します。 ただし、これも修正が必要です。
修正点は以下
- 文の削除
- -- CONNECT TO TPCD;
- -- COMMIT WORK;
- 各テーブル名からTPCDスキーマの削除
- 外部キーの追加文の修正
外部キーの追加文は
ALTER TABLE NATION ADD FOREIGN KEY NATION_FK1 (N_REGIONKEY) references REGION;
となっているものを
ALTER TABLE NATION ADD FOREIGN KEY (N_REGIONKEY) references REGION(R_REGIONKEY);
と変えました。 そして実行。
$ psql -d testdb -f dss.ri
データのロード、インデックスの追加はかなり時間がかかりますのでコーヒーでも飲みながら気長に待ちましょう。
Chefのまとめ
chefの勉強したので記録。
とりあえず、chefはここまでにして次は違うことをやるつもり。
1. 準備
$ knife solo init chef-repo $ cd chef-repo $ knife solo prepare [host名] ※[host名]はsshで接続できる名前 $ knife cookbook create [name] -o site-cookbooks/
そうするとこんな感じでディレクトリ・ファイルができる
chef-repo/
----- site-cookbooks/ | ||
------ [name]/ | ||
------ recipes/ | ||
------ default.rb =>編集対象、nodeで実行する内容を書く | ||
------ template/ ノードに送信するファイルを格納する。 | ||
------ nodes/ |
2. ノードで任意の処理を実行
やること
・default.rbの編集
・[host名].jsonの編集
その後、以下を実行。
$ knife solo cook [host名]
するとdefault.rbに書かれた内容が実行される。
何ができるの?
defaut.rbに書けるノードで実行するさまざまな命令を総称してResourcesという。
resourcesの例(一部)
package
さまざまなパッケージをインストールする
service
OSサービスをコントロールする
template
ファイルを操作する。erbファイルをtemplateフォルダに置くことで、その内容がノードに書かれる。
値を変数として埋め込むことができる。
gem_package
gemパッケージをインストールする
cookbook_file
ファイルを転送する
あとは、http://docs.opscode.com/chef/resources.html
を見て勉強すべし。
SSHの設定
$ vagrant ssh
というサブコマンドが用意されている。
でも、普通にsshコマンドでも接続したい場合もある。
その場合、ssh接続設定をvagrantサブコマンドから取得できる。
取得した情報は~/.ssh/configに書けばいい。それを一気にやるには以下のようにコマンドを打つ。
$ vagrant ssh-config --host [ホスト名] >> ~/.ssh/config
ただしこのとき、OpenSSHの最新バージョンを使っていると以下のように怒られるかもしれない。
$ ssh [ホスト名] Bad owner or permissions on /home/[OSユーザー名]/.ssh/config
これは、.ssh/configファイルのパーミッションの問題。
OpenSSHの最新版ではセキュリティが強化されているため、設定ファイルが他のユーザから見えないようにしていないと接続ができない。
なので、以下のようにパーミッションを変えて解決
$ sudo chmod 600 ~/.ssh/config
プロビジョニングとBox作成
Vagrantで仮想マシンを起動するときに、任意の操作を実行する。
Vagrantfileに以下を追加する。
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "centos32" config.vm.provision :shell,:inline => "echo hello world" #この行 end
ダブルクォーテーションでくくったシェルコマンドが実行される。
シェルのファイルを指定するには、
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "centos32" config.vm.provision :shell,:path => "provisioning.sh" #この行 end
とする。
おもむろにVagrantを使おうとしたが躓いた
- 準備
$ vagrant box add mybox [link]
で、ボックスを取得。myboxには好きな名前を付ける。
ボックスは
http://www.vagrantbox.es/
から持ってくる。
$ vagrant box list
で取得済みのリストを確認
- 仮想マシンの配備・起動
$ mkdir myVM $ cd myVM $ vagrant init mybox $ vagrant up
…がだめ。
以下のエラーが出た。
VirtualBox is complaining that the kernel module is not loaded. Please run `VBoxManage --version` or open the VirtualBox GUI to see the error message which should contain instructions on how to fix this error.
言われた通りにrunしてみる。
$ VBoxManage --version WARNING: The vboxdrv kernel module is not loaded. Either there is no module available for the current kernel (2.6.32-431.el6.i686) or it failed to load. Please recompile the kernel module and install it by sudo /etc/init.d/vboxdrv setup You will not be able to start VMs until this problem is fixed. 4.3.8r92456
やっぱり、素直にやってみる
# /etc/init.d/vboxdrv setup Stopping VirtualBox kernel modules [ OK ] Uninstalling old VirtualBox DKMS kernel modules [ OK ] Trying to register the VirtualBox kernel modules using DKMS Error! Your kernel headers for kernel 2.6.32-431.el6.i686 cannot be found at /lib/modules/2.6.32-431.el6.i686/build or /lib/modules/2.6.32-431.el6.i686/source. [失敗] (Failed, trying without DKMS) Recompiling VirtualBox kernel modules [失敗] (Look at /var/log/vbox-install.log to find out what went wrong)
失敗しやがった。
/lib/modules/2.6.32-431.el6.i686/
を見に行くと、なんとbuildのリンク先がおかしかったので修正。
build -> ../../../usr/src/kernels/2.6.32-431.el6.i686
から
build -> ../../../usr/src/kernels/2.6.32-431.5.1.el6.i686
やり直してみる。
# /etc/init.d/vboxdrv setup Stopping VirtualBox kernel modules [ OK ] Uninstalling old VirtualBox DKMS kernel modules [ OK ] Trying to register the VirtualBox kernel modules using DKMS[ OK ] Starting VirtualBox kernel modules [ OK ]
成功した。
このあと、 vagrant up したら仮想マシンの生成は成功するようになった。
でも、sshで接続しにいくとタイムアウトする。。。。これは、Vagrantfileの問題なようなので、とりあえずvagrant使える環境は整った。
Zaimのリクエストトークン取得ができない話
Javaの勉強のために「とりあえず、なにか作ろう」と思い、ZaimのAPIを叩いたアプリケーションを作ろうとしています。
が、最初の第一歩であるoauth認証で積んだのでメモ。
勉強も兼ねて、一から自分でやったる、と思って色々なところを参考にヘボクラスを作りました。
だが、Zaimのリクエストトークン用のURLにアクセスしても400を吐かれます。。。
しかし、Twitterで実験してみると、こちらでは上手くいきます。
ついでに、rubygemのoauthライブラリで実験したみたところ。やはりTwitterはリクエストトークンが返ってくるのに、Zaimでは400です。。。
というわけで、原因を調査中です。
public class OauthImpl { private URL url; private URLConnection ucon; private String consumerkey = ""; private String consumerSecret = ""; private String oauth_nonce = ""; private String oauthToken = ""; private String oauthTokenSecret = ""; private String oauthSignature=""; private String oauth_timestamp = ""; private SortedMap<String, String> params; public OauthImpl(String url,String consumerkey,String consumerSecret) { try { this.url = new URL(url); this.consumerkey = consumerkey; this.consumerSecret = consumerSecret; } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void httpGet() { HttpURLConnection huc = (HttpURLConnection) this.ucon; try { huc.setRequestMethod("GET"); huc.connect(); BufferedInputStream bis = new BufferedInputStream( huc.getInputStream()); int data; while ((data = bis.read()) != -1) System.out.write(data); } catch (ProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void sendRequestPost() throws Exception { this.oauth_timestamp = String.valueOf(new Long(System .currentTimeMillis() / 1000L)); double ran = Math.random(); this.oauth_nonce = Double.toString(ran); params = new TreeMap<String, String>(); params.put("oauth_consumer_key", consumerkey); params.put("oauth_signature_method", "HMAC-SHA1"); params.put("oauth_timestamp", this.oauth_timestamp); params.put("oauth_nonce", this.oauth_nonce); params.put("oauth_version", "1.0"); params.put("oauth_callback", "oob"); { //signature is constructed String paramStr = ""; // 昇順で並べる for (Entry<String, String> param : params.entrySet()) { paramStr += "&" + param.getKey() + "=" + param.getValue(); } // first "&" should be removed paramStr = paramStr.substring(1); String text; String signature = null; text = urlEncode("POST") + "&" + urlEncode(this.url.toString()) + "&" + urlEncode(paramStr); // System.out.println("text = \n"+text); String key = urlEncode(this.consumerSecret) + "&"; SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1"); Mac mac = Mac.getInstance(signingKey.getAlgorithm()); mac.init(signingKey); byte[] rawHmac = mac.doFinal(text.getBytes()); signature = BASE64Encoder.encode(rawHmac); this.oauthSignature = signature; params.put("oauth_signature", signature); } String paramStr = ""; for (Entry<String, String> param : params.entrySet()) { paramStr += "," + param.getKey() + "=\"" + urlEncode(param.getValue()) + "\""; } paramStr = paramStr.substring(1); String authorizationHeader = "OAuth " + paramStr; HttpURLConnection huc = (HttpURLConnection) this.url.openConnection(); huc.setRequestMethod("POST"); // huc.setDoOutput(true); // System.out.println(this.createAuthHeader()); huc.setRequestProperty("Authorization", authorizationHeader); huc.connect(); BufferedReader reader = new BufferedReader(new InputStreamReader( huc.getInputStream())); String response; while ((response = reader.readLine()) != null) { System.out.println(response); } } private String urlEncode(String str) { try { return URLEncoder.encode(str, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } }