vagrant の基礎

ansibleを触る環境を準備するためにvagrantを触ったのでその時のメモ

mac環境へのインストール

1.公式サイトからインストーラをダウンロードする。

https://www.vagrantup.com/downloads.html
/usr/local/bin/vagrantにインストールされた
~ which vagrant
/usr/local/bin/vagrant

2.vagrantfileの作成

# mkdir -p ~/vagrantspace/vagrant_getting_started    
# cd ~/mywork/vagrantspace/vagrant_getting_started    
# vagrant init

vagrant initでVagrantfileが作られる。Vagrantfileはvagrantのバージョンコントロールを行うためのファイルになる。

3.boxの追加

公式の手順に従ってhashicorp/precise64のboxを追加する。

# vagrant box add hashicorp/precise64

別のboxを追加する場合はatlasが提供している以下のダウンロードサイトから探すことができる。
https://atlas.hashicorp.com/boxes/search?_ga=1.197033387.661843880.1488614682
自前でisoを用意したい場合は、以下を参考にする。
http://kan3aa.hatenablog.com/entry/2015/05/29/120212

vagrantで使用するダウンロード済みboxの一覧を確認する場合は以下を実行する。

# vagrant box list

4.vmを起動して接続する

VirtualBoxをインストールしていないのであれば、公式からインストーラーをダウンロードして入れておく。
https://www.virtualbox.org/wiki/Downloads
vmの起動

# vagrant up

vmssh接続する

# vgrant ssh

vm接続を解除する

# logout
又は
# exit
vagrant基本コマンド
再起動
vagrant reload

ステータス確認
vagrant status

一時停止
vagrant suspend

一時停止からの復帰
vagrant resume

停止
vagrant halt

起動
vagrant up

boxの初期化
vagrant init

boxの削除
vagrant destory
vagrantの起動状態を確認する

status管理用のプラグインインストール

# vagrant plugin install 
# vagrant global-status

ディレクトリの共有

通常Vagrantfileはssh接続後の/vagrant/Vagrantfileにマウントされる。

# ls /vagrant/

/vagrantディレクトリ直下にファイルを作成したらvmのホスト側のVagrantfileがあったディレクトリにファイルが作られる動きをする。

# touch /vagrant/hoge
# exit
# ls

5.vagrant起動時のスクリプトapacheのインストール

以下のapacheインストールスクリプトをbootstarp.shのファイル名でVagrantfileがあるディレクトリに保存しておく。 # vi /vagrant/bootstrap.sh

#!/usr/bin/env bash

apt-get update
apt-get install -y apache2
if ! [ -L /var/www ]; then
  rm -rf /var/www
  ln -fs /vagrant /var/www
fi

それから設定ファイルを編集し/vagrantディクトリにbootstrap.shをvagrant起動時に実行するスクリプトにす指定する。

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
  config.vm.provision :shell, path: "bootstrap.sh"
end

次にvagrant reloadして再起動

# vagrant reload --provision
# vagrant up

vagrantssh接続している状態でapacheにアクセスできるか確認

# wget -qO- 127.0.0.1

6.ポートフォワード

ホスト端末からvagrantへアクセスできるようにポートフォワードを設定する
# vi Vagrantfile

config.vm.network "forwarded_port", guest: 80, host: 4567

ホスト端末からブラウザでlocalhost:4567にアクセスして動作確認

PyMongo覚書

Pymongoの覚書になります、と言ってもmongoのクライアントから直接実行するのとほとんど同じように使うことができます。

モジュールインポート
import json
import re
import pymongo

import bson
from bson.son import SON
from bson.code import Code
from pymongo import MongoClient
from bson.code import Code
from datetime import datetime, timedelta
DB接続

事前に外部接続を許可する等して接続できるようにしておく必要があります。

mongo_client = MongoClient('ホスト名:27017')
db=mongo_client['DB名']
コレクションの一覧確認
for c in db.collection_names():
    print(c)
||

*** インサート
>|python|
# インサート
db.book_collection.insert_one(
    {
        'category': 'it',
        'title':  '入門 python3',
        'synopsis': 'Pythonが誕生して四半世紀。データサイエンスやウェブ開発、セキュリティなどさまざまな分野でPythonの人気が急上昇中です。',
        'publish': 'オライリー',
        'authors': ['Bill Lubanovic', '斎藤康毅', '長尾高弘'],
        'created': datetime.strptime("2015-12-01", "%Y-%m-%d")
    }
)

以下の検索、集約では上でインサートしたフィールド情報を持ったコレクションを使って行います。

検索
# 条件なし検索
for c in db.book_collection.find().limit(5):
    print(c)

# ○条件付き created > "2016-09-01"
for c in db.book_collection.find({'created': {'$gt': datetime.strptime("2016-09-01", "%Y-%m-%d")}}).limit(5):
    print(c)

# ◯複数条件 created > "2016-09-01" と category = 'fantasy'
for c in db.book_collection.find({
        'created': {'$gt': datetime.strptime("2016-09-01", "%Y-%m-%d")},
        'category': 'fantasy'
    }).limit(5):
    print(c)
    
#◯条件 authorsに田中太郎が含まれる
for c in db.book_collection.find({'authors': {"$in":[u"田中太郎"]}}).limit(5):
    print(c)

# ◯条件指定を変数に格納する created > "2016-10-01"
condition={'created': {'$gt': datetime.strptime("2016-10-01", "%Y-%m-%d")}}
for c in db.book_collection.find(condition).limit(5):
    print(c)

# ソート
# ◯createdで昇順にソート
for c in db.book_collection.find({},{'title': 1, 'created': 1} ).sort('created', pymongo.DESCENDING):
    print(c) 
集約
# 集約
# ◯publishで集約した件数を表示
for c in db.book_collection.aggregate([
        { '$group' : {'_id': "$publish", 'count':{ '$sum': 1 } }}
]):
    print(c)

# ◯createdの年、月、日で集約した件数を表示
for c in db.book_collection.aggregate([
        { '$group' : {'_id': {'month': { '$month': '$created'}, 'day': { '$dayOfMonth': '$created' }, 'year': { '$year': "$created" }}, 'count':{ '$sum': 1 } }}
]):
    print(c)


#◯publichとcreatedの年で集約した件数を表示
for c in db.book_collection.aggregate([
        { '$group' : {'_id': {'publish': "$publish", 'year': { '$year': "$created" }}, 'count':{ '$sum': 1 } }}
]):
    print(c)

# ◯createdの年、月、日で集約してソートした件数を表示
for c in db.book_collection.aggregate([
        { '$group' : {'_id':{'year': { '$year': "$created" }, 'month': { '$month': "$created" } }, 'count':{ '$sum': 1 } }},
        { '$sort': {'_id.month':1}}
]):
    print(c)


# ◯createdの年、月、日で集約し件数上位3件を表示
for c in db.book_collection.aggregate([
        { '$group' : {'_id':{'year': { '$year': "$created" }, 'month': { '$month': "$created" } },'count':{ '$sum': 1 } }},
        { '$sort': {"count":-1}},
        { '$limit': 3 }
]):
    print(c)

# ◯authorに田中太郎が含まれるものをpublichで集約して表示
for c in db.book_collection.aggregate([
        { '$match': {'authors': {"$in":['田中太郎']}}},
        { '$group' : {'_id': "$publish", 'count':{ '$sum': 1 } }},
        { '$sort': {"count":-1}}
]):
    print(c)

# マップリデュースによるpublishごとの集約
mapper = Code("""
        function () {
            emit(this.publish, 1);
        }
 """)

reducer = Code("""
        function (key, values) {
            var total = 0;
            for (var i = 0; i < values.length; i++) {
                total += values[i];
            }
            return total;
        }
""")

result = db.book_collection.map_reduce(mapper, reducer, "myresults")
for doc in result.find():
    print(doc['_id'], ':', doc['value'])

MongoDB覚書

MongDB

MongoDBをcliから操作時のメモです。Mngoのインストール等を試した環境はCentOS7.2になります。

CentOS7環境でのインストール

リポジトリ追加 公式ページを確認しyumリポジトリを追加する(https://www.mongodb.com/download-center#community)

/# vi /etc/yum.repos.d/mongodb.repo

[mongodb-org-3.4]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc

MongoDB起動

# systemctl start mongod

mongo接続

# mongo

mongo接続終了

exit

外部アクセスを許可する(IP指定なし)

/# vi /etc/mongod.conf

net:
  port: 27017
  #bindIp: 127.0.0.1,192.168.1.15

bindIpを未指定または"bind_ip: 0.0.0.0"にすることで接続元のIPアドレスを制限しないようにできます。

外部アクセスを許可する(IP指定あり)

/# vi /etc/mongod.conf

net:
  port: 27017
  bindIp: 127.0.0.1,192.168.1.15

bindIpを指定することでアクセス元のIPアドレスを制限できます。

bsonのリストア

# mongorestore –host localhost –db DB名 bsonファイル

DB一覧表示

show dbs

DBの選択

use DB名

DBの作成

use DB名

コレクションの作成

db.createCollection(“test_collection”)

DBの削除

use DB名 db.dropDatabase()

コレクション一覧確認

show collections

挿入

db.コレクション名.insert({
  フィールド名:値,,,,
})

サンプル
db.book_collection.insert({
 category: 'fantasy',
  title: 'タイトル1',
  synopsis: 'あらすじ1',
  publish: '田中出版',
  authors: ['田中太郎', '佐藤賢作'],
  created: ISODate("2016-11-29"),
})

検索

◯テストデータ
db.book_collection.insert({
 category: 'fantasy',
  title: 'タイトル1',
  synopsis: 'あらすじ1',
  publish: '田中出版',
  authors: ['田中太郎', '佐藤賢作'],
  created: ISODate("2016-11-29"),
})
db.book_collection.insert({
 category: 'horror',
  title: 'ホラー1',
  synopsis: ' ホラー1',
  publish: '竹中出版',
  authors: ['田中太郎', '伊藤優一'],
  created: ISODate("2016-08-21"),
})
db.book_collection.insert({
 category: 'fantasy',
  title: 'ファンタジー2',
  synopsis: ' ファンタジー2',
  publish: '田中出版',
  authors: ['加藤信之'],
  created: ISODate("2016-07-15"),
})

db.book_collection.insert({
 category: 'SF',
  title: 'SF1',
  synopsis: ' SF1',
  publish: 'はなまる文庫',
  authors: ['田中賢介'],
  created: ISODate("2016-09-15"),
})

db.book_collection.insert({
 category: 'SF',
  title: 'SF2',
  synopsis: ' SF2',
  publish: 'はなまる文庫',
  authors: ['田中賢介'],
  created: ISODate("2016-09-16"),
})
○一度に取得する件数変更(デフォルトでは20件ずつのデータ取得になっていたはず)
DBQuery.shellBatchSize = 200


○条件なし
db.コレクション名.find()

◯条件付き x > 1
db.コレクション名.find({x: {$gt: 1}})


○条件付き created > "2011-11-01"
db.コレクション名.find({created: {$gt: ISODate("2011-11-01T00:00:00+09:00")}})

◯複数条件 created > "2011-11-01" と category = 'fantasy'
db.コレクション名.find({
      created: {$gt: ISODate("2011-11-01T00:00:00+09:00")},
      category: 'fantasy'
      }
)
・sample
db.book_collection.find({
      created: {$gt: ISODate("2011-11-01T00:00:00+09:00")},
      category: 'fantasy'
      }
)

◯条件 authorsに田中太郎が含まれる
db.コレクション名.find({authors: {"$in":['田中太郎']}})


◯条件 作者の名前が田中で前方一致する
db.コレクション名.find({authors: {"$in":[/^田中/]}})
*/をつける時はシングルクォーテーションを外さないと見つからなかった

◯表示するフィールドを指定する titleのみ表示
db.コレクション名.find({}, {'title': 1})


◯条件指定を変数に格納する created > "2016-08-01"
condition={created: {$gt: ISODate("2016-08-01T00:00:00+09:00")}}
db.コレクション名.find(condition)

◯表示条件を変数に格納する titleのみ表示
view={title:1}
db.コレクション名.find({}, view)

ソート

◯createdで昇順にソート
db.コレクション名.find().sort({created:1})

集約

◯publishで集約した件数を表示
db.コレクション名.aggregate([
        { $group : {_id: "$publish", count:{ $sum: 1 } }}
])


◯createdの年、月、日で集約した件数を表示
db.コレクション名.aggregate([
        { $group : {_id: {month: { $month: "$created" }, day: { $dayOfMonth: "$created" }, year: { $year: "$created" }}, count:{ $sum: 1 } }}
])

◯publichとcreatedの年で集約した件数を表示
db.コレクション名.aggregate([
        { $group : {_id: {publish: "$publish", year: { $year: "$created" }}, count:{ $sum: 1 } }}
])

◯createdの年、月、日で集約してソートした件数を表示
db.コレクション名.aggregate([
        { $group : {_id:{year: { $year: "$created" }, month: { $month: "$created" } },count:{ $sum: 1 } }},
        { $sort: {"_id.month":1}}
])

◯createdの年、月、日で集約し件数上位3件を表示
db.コレクション名.aggregate([
        { $group : {_id:{year: { $year: "$created" }, month: { $month: "$created" } },count:{ $sum: 1 } }},
        { $sort: {"count":-1}},
        { $limit: 3 }
])

◯authorに田中太郎が含まれるものをpublichで集約して表示
db.コレクション名.aggregate([
      { $match: {authors: {"$in":['田中太郎']}}},
        { $group : {_id: "$publish", count:{ $sum: 1 } }},
        { $sort: {"count":-1}}
])

CentOS7でユーザのコマンドに制限をかける

以前特定のコマンドしか実行できないユーザを作る必要があった時にrbashを使用したのが便利だったので、その時のメモになります。確認した環境はCentOS 7.2になります。

1. rbashを使えるようにする
# ln -s /bin/bash /bin/rbash
# vi /etc/shells

/bin/rbash ←この行を追加

2. 実行シェルの変更
# su 制限するユーザ
$ cssh
新しいシェル [/bin/bash]: /bin/rbash ←「/bin/rbash」を入力

3. bash_profileの所有者変更および
rootにユーザーを切り替えてtenda_keieiのbash_profileの所有者と所有グループを変更
# chown root:root ./bash_profile
# chmod 755 .bash_profile

4. 実行可能コマンドの設定
# mkdir /home/制限するユーザ/command
# ln -s /usr/bin/java /home/制限するユーザ/java
# ln -s /usr/bin/date /home/制限するユーザ/date
# ln -s /usr/bin/mv /home/制限するユーザ/mv

 
5. 実行可能コマンドをpathに追加
# vi /home/tenda_keiei/.bash_profile

# settings for rbahs
# PATH=$PATH:$HOME/.local/bin:$HOME/bin
PATH=/home/制限するユーザ
export PATH=$PATH:/home/制限するユーザ/command

export PATH

javaで作ったバッチを実行するときとか
・実行するスクリプトの置き場所もpathに追加しておく
javaコマンドでクラスパスを指定する場合、bash_profileないで事前にクラスパス用の環境変数を用意しておき、それを使うようにする(rbashでは/を含んだコマンドを実行できない!)

◯その他
コマンド制限かけたユーザでバッチを実行する場合は以下の点に注意が必要になります。
・cronはrbashを有効にする前であれば設定できる。
・cronの場合にbash_profileで設定した環境変数が使えなかったら、rootユーザとかでにcronを設定しておきsourceで読み込ませる。(制限ユーザに対してsourceコマンドを有効にすることでも対応可能かは未確認です。)
0 3 * * * source /home/ruser/.bash_profile; ◯◯◯.sh

Chainerで簡単なクラス分類をしてみる

Chainerを試してみるために簡単なサンプルプログラムを動かしてみたいと思います。

まず必要なライブラリをインポートします。

import numpy as np
import chainer
from chainer import cuda, Function, gradient_check, Variable
from chainer import optimizers, serializers, utils
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L

それから、学習用データを読み込みます。今回はsklearnからアヤメのデータを使って4入力(がくの長さ、幅と茎の長さ、幅)からアヤメの種類(setosa, versicolor, virginica)を分類できるように試してみます。

# Set data
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data.astype(np.float32)
Y = iris.target.astype(np.float32)
N = Y.size
Y2 = np.zeros(3 * N).reshape(N,3).astype(np.float32)
for i in range(N):
    Y2[i,np.int(Y[i])] = 1.0

index = np.arange(N)
xtrain = X[index[index % 2 != 0],:]
ytrain = Y2[index[index % 2 != 0],:]
xtest = X[index[index % 2 == 0],:]
yans = Y[index[index % 2 == 0]]

モデルの定義として4入力、3出力で中間層はなしのものを定義しています。入力に対して出力が簡単に結びつくような今回のケースでは中間層は必要なさそうに思います。多クラスの分類としてはソフトマックス関数を使用し誤差関数として二乗誤差を使用しています。ソフトマックスを利用した多クラス分類等では交差エントロピーを使うように思っていたのですが、この辺りはちゃんと学習して使いこなせるようにしたいと思います。

# Define model
class IrisRogi(Chain):
    def __init__(self):
        super(IrisRogi, self).__init__(
            # 入力4軸(がくの長さ、幅と茎の長さ、幅) 出力3クラス分類(irisの種類setosa, versicolor, virginica)
            l1=L.Linear(4,3),
        )

    def __call__(self,x,y):
        # 順伝番した結果に対してmean_squared_errorで二乗誤差求めている
        return F.mean_squared_error(self.fwd(x), y)

    def fwd(self,x):
        # 多クラス分類(irisの種類)のための各ユニットの出力としてソフトマックスを使用する
        return F.softmax(self.l1(x))

# Initialize model

model = IrisRogi()
# パラメータの最適化で比較的高速に良い値を出すadamを使用する
optimizer = optimizers.Adam()
optimizer.setup(model)


それから学習を行います。

# Learn

n = int(index.size / 2)
bs = 25
for j in range(5000):
    sffindx = np.random.permutation(n)
    accum_loss = None
    for i in range(0, n, bs):
        x = Variable(xtrain[sffindx[i:(i+bs) if (i+bs) < n else n]])
        y = Variable(ytrain[sffindx[i:(i+bs) if (i+bs) < n else n]])
        model.zerograds() # 勾配を初期化
        loss = model(x,y) # 順方向に計算し誤差を算出
        loss.backward() # 逆伝番で勾配の向きを計算
        optimizer.update() # 逆伝番で得た勾配からパラメータを更新する

学習で得たパラメータを利用しテストをしてみます。

# Test
xt = Variable(xtest, volatile='on')
yy = model.fwd(xt)

ans = yy.data
nrow, ncol = ans.shape
ok = 0
for i in range(nrow):
    cls = np.argmax(ans[i,:])
    # print( ans[i,:], cls)
    if cls == yans[i]:
        ok += 1

print (ok, "/", nrow, " = ", (ok * 1.0)/nrow)

自分の環境で動かしてみたところ、73/75の精度で正解していたのでちゃんと動いてることは確認できます。

Scalaのfor式とflatMapについて

自分は職場では良くjava7でプログラミングするのでjava8のStream APIなどを触ることがないのですが、そのような状態だとscalaのfor式やflatMapに抵抗があったので簡単に使い方だけでもおさらいしてみたいと思います。

まず、動作確認で使うクラスは以下になります。Todo管理用のクラスを用意し、特定の作業者のタスクを検索するプログラムを試します。

  case class Todo(
    TodoId: Int, 
    CategoryId: Int, 
    Title: String, 
    Text: String, 
    Order: Int, 
    worker: List[String]){
    override def toString = Text
  }
  case class TodoCategory(
    CategoryId: Int, 
    Category: String, 
    Order: Int, 
    TodoList: List[Todo])

それから動作確認ようデータは以下になります。

  val collecting_doc = 
    Todo(1, 1, "collect data", "資料を集める", 1, 
      List("sato", "nakata"))
  val prepare_tool = 
    Todo(2, 1, "prepare tool", "ツールを準備する", 2, 
    List("kato", "nakata"))
  val investigate = 
    Todo(3, 2, "investigate", "調査する", 1, 
    List("sato"))
  val summarize_result = 
    Todo(4, 2, "summarize result", "調査結果をまとめる", 2, 
    List("kato", "nakata"))
  val review = 
    Todo(5, 2, "review", "レビューを受ける", 3, 
    List("sato", "nakata"))
  val presentation = 
    Todo(6, 3, "presentation", "発表する", 1, 
    List("sato"))
  val improve = 
    Todo(7, 3, "improve", "改善する", 2, 
    List("sato"))

  val done = TodoCategory(1, "完了", 1, 
    List(collecting_doc, prepare_tool))
  val doing = TodoCategory(2, "実施中", 2, 
    List(investigate, summarize_result, review))
  val next = TodoCategory(3, "待ち", 3, 
    List(presentation, improve))

  val allTodo: List[TodoCategory] = List(done, doing, next)

for式を使い特定の作業者のタスクを検索する場合は以下のようになります。

  def workerTaskFor(name: String): List[Todo] ={
    for(
      category <- allTodo;
      todo <- category.TodoList;
      tw <- todo.worker
      if tw eq name
    ) yield todo
  }

"category <- allTodo;"の部分でallTodoの一つずつの要素がcategoryには入ります。同様にtw <- todo.workerではtodoに設定されている一人一人のwoerkerが入り if tw eq nameにより名前での絞り込みを行っています。最後にyield todoの部分で絞り込まれたtodoでListを作成しています。


次にflatmapを使った場合は以下のようになります。

  def workerTaskFlatmap(name: String): List[Todo] = {
    allTodo flatMap(category =>
      category.TodoList flatMap( todo =>
        todo.worker withFilter (worker => worker eq name) map( 
          worker =>
            todo
        )
      )
    )
  }

やっていることはfor式と同じなのですがworkerの絞り込みにwithFilterというコレクションAPIを使用しています。コレクションAPIはTraverable を実装するコレクションクラスで利用することができ、これに慣れておくとデータの操作周りがすごい快適になると思います。自分の実感からもこの辺りになれるかどうかでScalaに感じる抵抗がぐっと変わってくるのかなという気がします。

最後にプログラムの全体は以下のようになりました。

object MyStudy {
  case class Todo(TodoId: Int, CategoryId: Int, Title: String, Text: String, Order: Int, worker: List[String]){
    override def toString = Text
  }
  case class TodoCategory(CategoryId: Int, Category: String, Order: Int, TodoList: List[Todo])

  val collecting_doc = Todo(1, 1, "collect data", "資料を集める", 1, List("sato", "nakata"))
  val prepare_tool = Todo(2, 1, "prepare tool", "ツールを準備する", 2, List("kato", "nakata"))
  val investigate = Todo(3, 2, "investigate", "調査する", 1, List("sato"))
  val summarize_result = Todo(4, 2, "summarize result", "調査結果をまとめる", 2, List("kato", "nakata"))
  val review = Todo(5, 2, "review", "レビューを受ける", 3, List("sato", "nakata"))
  val presentation = Todo(6, 3, "presentation", "発表する", 1, List("sato"))
  val improve = Todo(7, 3, "improve", "改善する", 2, List("sato"))

  val done = TodoCategory(1, "完了", 1, List(collecting_doc, prepare_tool))
  val doing = TodoCategory(2, "実施中", 2, List(investigate, summarize_result, review))
  val next = TodoCategory(3, "待ち", 3, List(presentation, improve))

  val allTodo: List[TodoCategory] = List(done, doing, next)


  def main(args: Array[String]): Unit ={

    workerTaskFor("nakata") foreach(println)

    workerTaskFlatmap("nakata") foreach(println)

  }

  def workerTaskFor(name: String): List[Todo] ={
    for(
      category <- allTodo;
      todo <- category.TodoList;
      tw <- todo.worker
      if tw eq name
    ) yield todo
  }

  def workerTaskFlatmap(name: String): List[Todo] = {
    allTodo flatMap(category =>
      category.TodoList flatMap( todo =>
        todo.worker withFilter (worker => worker eq name) map( 
          worker =>
            todo
        )
      )
    )
  }
}

分析方法調査

○主成分分析

主成分分析とは
主成分分析は多くの変数を持っているデータを少ない変数、通常は2つ~3つの
変数に縮約してデータを分析する際に多くもちいられている

x1, x2 の変数が合った場合に z1=ax1+bx2となる合成変数z1を作成することにより
変数を減らしている

1.2主成分分析の基礎
n個の個体(データ数)、p個の変数により構成されたデータセットXn*pがあるとする
このp次元のデータをより低いk次元に集約するには以下の変換を行う
z1 = a11x1 + a21x2 + ・・・ + ap1xp
z2 = a12x1 + a22x2 + ・・・ + ap2xp

zj = a1jx1 + a2jx2 + ・・・ + apjxp

zk = a1kx1 + a2kx2 + ・・・ + apkxp

合成変数ができるだけ多くの情報量を持つようにするため、データの散らばり具合(分散)に着目します。分散=情報量といえるからです。
そのためにはΣaij^2=1になる制約を付けた上で最大になるzjを求める
制約条件によりラグランジュの乗数法を用いることができる

○因子分析
扱うデータの形式が主成分分析と基本的に同じであることから似たような場面で利用される
主成分分析では夢想間の合成変数を求めることで多くの変数を少ない変数に縮小するが、
因子分析で変数間の相関関係から共通因子を求めることで、多くの変数を共通因子にまとめて
説明する
主成分分析は合成の分析であるのに対し、因子分析は分解の分析といえる。
因子分析を使う目的としては以下2つがあるといわれている
・少数の説明要因に話をまとめるため
・(調査対象者の)回答の奥に潜む要因をまとめるため

因子分析で得られる指標
因子負荷量
→各変数と各因子の相関を表す。
共通性
→各変数と因子空間の相関を表す(各変数が因子軍によってどれだけ説明できるかを示すもの)。
0から1の値を取り、道擬かれた因子群で全て説明できるときに1になる。
銃相関係数の2乗を用いて共通性を推定すると、共通性は各因子負荷量の2乗和になる
寄与率:
→ある因子がどの程度の説明力を持っているか割合を表す。

○対応分析(コレスポンデンス分析)
対応分析の考えは、行列(分割表)において、行項目と列項目の相関が最大になるように、行と列の双方を並び替えることです。
対応範囲は広くローデータからでもクロス集計表からでも分析ができる。ブランドイメージの分析などで頻繁に用いられる。
結果に対しては以下の注意が必要
・軸に意味づけをした方が、結果の解釈がしやすい。この場合、意味がつけやすいように軸を回転させてもよい。
・関連の強いカテゴリは近くに、弱いカテゴリは遠くにプロットされるが、これはあくまでカテゴリ間の相対的な関係で、絶対的なボリュームを表わすものではない。
・縦軸の目盛りと横軸の目盛りはあわせた方がよい。そうしないと距離を見誤ることがある。
・ただしこのとき、縦軸と横軸の選んだ軸の固有値(あるいは寄与率)に注意する必要がある。
・クロス集計表から作成しているので、サンプルサイズは結果に反映されない。サンプルサイズが少ない際には注意が必要。(ブランドイメージを質問するときなど、認知者だけに質問すると、ブランドごとのサンプルサイズが異なるので注意する。例えば、Aブランドは認知者が10人で、5人が「はい」と答えて50%、Bブランドは認知者が100人で、50人が「はい」と答えても50%で、この差は結果に反映されない。)
・異なる項目、例えば前の例では、飲料と飲用シーンのカテゴリの位置関係は、原点からの方向で判断する。原点から見て同じ方向にあれば、一見距離があっても、同様の意味づけが可能である。

データの構造を再現する面では主成分分析より効果が劣るが、パターンを分類する面では主成分分析よりよい結果を示すケースが多い。
分割表の独立性の問題では、通常カイ2乗統計量を用い、これにより行列の変換処理を行う。

・多重対応分析
アンケート結果の分析を行うときに、回答結果の変換表(未記入だったら0にするとか)を使って分析することを多重対応分析と呼ぶ

対応分析は結果が図になってやりたいことのイメージはつきやすいが、それを求めるためのアルゴリズム複数存在する。

○多次元尺度法(MDS)
複数の異なる手法の総称のこと。
例えば各地点間の距離を表す表があったとしたら、その表から各地点の2次元座標軸を割り出しそのデータに基づいてデータ解析を行う。
ブランド同士が似ているかどうかという度合いをポジショニングマップを作ってあらわしたりもする。
各地点の距離を現す表から2次元座標軸の表であれば最適なアルゴリズムを選んで実施すればよいが、ブランドイメージなどであれば
まずブランド間の類似度をどうやって求めるのかが課題になりそう。
mdsのインプットとしては各データ間の距離(類似度)データは持っておく必要がある

・非軽量MDS
距離の性質を持たない類似性データを視野に入れた場合のMDS

クラスター分析
異なる性質のものが混ざりあっている集団(対象)の中から互いに似たものを集めて集落(クラスター)を作り、対象を分類する。
分類方法として距離・あるいは類似度を用いる階層的クラスター分析、指定したグループの数に基づいてグループ分けする
k平均法、確率分布を仮定したグループわけがある。

・階層的クラスター分析
個体間の類似度あるいは非理事度に基づいて、最も似ている固体から順次に集めてクラスターを作っていく手法
樹形図で洗わせられるのでどのように階層が分けられているのかわかりやすいが、分類数が多くなるとk平均法に
比べても計算量が大きくなるというネックがある。

分析プロセスは以下のようになっている
1.データから距離(あるいは類似度)を求める。
2.クラスター分析の方法(最近隣方、最遠隣法など)を選択する
3.選択された方法のコーフェン行列を求める
4.コーフェン行列に基づいて樹形図を作図する
5.結果について検討する
コーフェン行列とは、個体間の距離を要素に持つ行列である。

クラスター分析の方法には以下のようなものがある
・最近隣法
・最遠隣法
・群平均法
・重心法
・メディアン法
・ウォード法

・非階層的クラスター分析(k-means)
階層的クラスター分析に比べて複数の個体をグループにまとめて、グループ間の距離(類似度)を使うことで
高速に処理を行えるようにしている。

k平均法の大まかな流れは以下になる
1.k個のクラスター中心(seed)の初期値を適当に与える
2.全てのデータをk個のクラスター中心との距離を求め、最も違いクラスターに分類する
3.形成されたクラスターの中心を求める
4.クラスターの中心が変化しない時点までステップ2,3を繰り返す

○自己組織化マップ
教師データを持たないニューラルネットワークのパターン分類方法
高次元データを2次元平面状へ非線形射影するデータ解析方法であり、
多次元尺度法、クラスター分析法として用いられている

自己組織化マップ(SOM:Self-Organizing Map)のプロセス
1.入力xjと出力層の全てのユニットと比べ、もっとも類似しているユニットを
探し出し、そのユニットを勝者とする。
2.探し出したユニット及びその近傍のユニットの重みベクトルmiを更新する。
3.全ての入力の特徴ベクトルxj(j=1,2,3...n)に対して1,2を繰り返し実行する。

○線形回帰分析
1つの説明変数を用いる単回帰分析、複数の説明変数を用いる重回帰分析、
変数及びモデルの選択、変数の相互作用を考慮したモデルなどある

重回帰分析で、注意すべきことは、本来説明変数間は独立であるべきという仮定です。
説明変数A、B間に相関が高いと、目的変数は、Aによって説明されるのか、Bによって説明されるのか判然とせず、
適切な偏回帰係数が求められません。これを、多重共線性(マルチコリニアリティ)といいます。
多重共線性は、偏回帰係数の符号が逆転することなどによって発見されることが多いのですが、説明変数間の相関行列を
調べることで発見できます。

非線形回帰分析
まず非線形モデルとは線形も出る以外のもののことであり、線形モデルは目的変数を説明変数の線形関数で表現するモデル
である。データによっては対数変換のような変換により非線形のデータを線形にすることも可能。

ロジスティック回帰ではy=a/(1+be^(cx))であらわす
多項式回帰はy=a+bx+cx^2+dx^3のようにあらわっされる

・一般化線形モデル
→線形回帰分析では残差が正規分布に従うと仮定していたが、一般化線形モデルは正規分布に従うことを保障せず
正規分布を拡張した分布族に対応させ非線形の現象を線形モデルの場合と同じく簡単に扱えるようにする。
線形モデルではXを説明変数、Yを目的変数、Aを係数、Eを誤差行列としてY=XA+Eで表せられる。一般化線形モデル
では非線形関数をg(μ)=XAに変換し線形も出るとして扱う。

○線形判別分析
目的変数が質的データである教師データを用いる判別分析及びパターン認識のもっとも木補填的な方法
判別分析は個体がどのグループに属するかが明確である学習データを用いて判別モデルを構築し、そのモデル
を用いて所属不明の個体がどのグループに帰属するかを判別する方法。
判別分析は線形判別分析と非線形判別分析に大別される。

非線形判別分析
非線形判別分析では二次関数を用いた判別分析方法、距離による判別法、多数決による判別分析法、
ベイズ判別分析法などがある。

○生存分析
イベントが起きるまでの時間とイベントとの間の関係に終点を当てる分析方法
工学分野における機械システムや製品の故障、医療分野における疾患の病気の再発
や死亡などを対象とした研究分野である

○時系列
時間と共に変動する現象に対して時間の順序で測定、観測した結果を記録したデータを時系列データと呼ぶ。
日常生活の中では株価及び為替レートのような金融・経済データなどで用いられる

○樹木モデル
非線形回帰分析、非線形判別分析の1つの方法であり、回帰問題では回帰木、分類問題では分類器あるいは
決定木と呼ばれている。

樹木モデルの基礎
CHAID(CHi-squared Automatic Interaction Detection)は分岐基準としてカイ2乗統計量やF統計量などが
用いられている。
C4.5/C5.0/See5は分岐の基準として利得比を用いている。

分類木(決定木)
分岐点の計算にジニ係数またはエントロピーを用いている

回帰木
回帰木で用いる分類基準は、実測時yiとセルの平均値μ[i]との差の2乗の和である。