2014年8月27日水曜日

Machine Learning (Andrew Ng) @ Coursera その5

Classification

binary classification problem

線形回帰は覚えたけど、これを分類問題に適用することはいい考えではない。
そこでロジスティック回帰が出てくる。

ロジスティック回帰は回帰というくせに分類問題に使われてて、
離散的な分類値に対して、0~1の値を取る関数を当てはめる。


Advanced Optimization

これまでは最急降下法を最適化アルゴリズムとして採用してきたが、
もちろんこれ以外にも最適化アルゴリズムが存在している。
例えば、
Conjugate gradient
BFGS
L-BFGS

と言った具合に。

ただ、数値計算のエキスパート出ない限りは直接実装するべきではない。
まずはライブラリ使うべき。
機械学習のライブラリを試していいライブラリを使ってまずは慣れる。
その中でいい実装悪い実装を見分ける。
Octaveはアドバンスドな最適化アルゴリズムが提供されているのでとりあえずはそれ使う。

optimset() と fminunc() をつかってアドバンスドな最適化を行う。
使い方としては、コスト関数の各パラメータに関する偏微分値とコスト関数値を返す関数を引数として渡すだけっぽい。


Multiclass classification

複数クラスの分類問題についての話。
複数クラスの教師セットを与えられた時は、one vs all(one vs rest) と呼ばれる分類問題を解くことになる。

A,B,Cに属するクラスは、Aと(B,C)に属するクラスで教師セットを分けて、
それらの決定境界を導出する。 
=> Aになる確率が求まる。

Bと(C,A)に属するクラスで教師セットを分けて、分類器を適用し決定境界を導出。
=> Bになる確率が求まる

Cと(A,B)に属するクラスで教師セットを分けて、分類器を適用し決定境界を導出。
=> Cになる確率が求まる

確率を比較して一番大きい物を採用すれば良い。



Machine Learning (Andrew Ng) @ Coursera その4


自学自習でOctaveの設定変更してみた。
Octave起動するといろいろ設定がdefault臭してすごく効率が悪い。
こういったときは .bashrc ならぬ、 octaverc なるものがあるんですわ。
この設定ファイルは、パス的には以下になります。
( 私のインストール先はCドライブ直下なのでその辺は読み替えて下さい。 )
 C:\Octave\3.2.4_gcc-4.4.0\share\octave\site\m\startup


で、2つの欲望を叶えるためoctavercを書き換えます。

1つは、起動時から自分の作業ディレクトリに飛びたい
2つは、糞長いプロンプトをPython風に ">>" にしたい

夢を叶えるスクリプトは以下のとおり。

## System-wide startup file for Octave.
##
## This file should contain any commands that should be executed each
## time Octave starts for every user at this site.
cd D:\Octave # Move to working directory
PS1(">>") # Change prompt

全然難しくないですね。


Plotting Data


clear;
t  = [0:0.01:0.98];
y1 = sin(2*pi*4*t);
y2 = cos(2*pi*4*t);
plot(t,y1);
hold on; # hold figures to overlap plotting
plot(t,y2, "r");
xlabel("time");
ylabel("value");
legend("sin", "cos");
title("my plot");
close;
cd "data"
print -dpng "myPlot.png" # png is file format
cd ".."
figure(1); plot(t, y1);
figure(2); plot(t, y2);
subplot(1,2,1); # Divides plot 1×2 grid, access first element
plot(t,y1);
subplot(1,2,2); # Divides plot 1×2 grid, access first element
plot(t,y2);
axis([0.5 1 -1 1]);
clf;
A = magic(5);
imagesc(A);
imagesc(A), colorbar, colormap gray; # three commands at the same time called comma chaining

Control Statements

v = zeros(10,1);
for i=1:10,
    v(i) = 2^i;
end;
indices = 1:10;
for i=indices,
    disp(i);
end;
i = 1;
while i <= 5,
    v(i) = 100;
    i = i+1;
end;
i=1;
while true,
    v(i) = 999;
    i=i+1;
    if i == 6,
        break;
    end;
end;
v(1) = 2;
if v(1) == 1,
    disp("The value is one.");
elseif v(1) == 2,
    disp("The value is two.");
else
    disp("The value is not one or two.");
end;
# exit # quit octave
# Add search path
addpath('D:\Octave\lib'); # don't use double quatation
squareThisNumber(5)

# cost function
X = [1 1; 1 2; 1 3]; # design matrix
y = [1; 2; 3]; # y axis values
theta = [0; 1];
j =  costFunctionJ(X,y,theta);

Vectorization



シグマ記号で定式化するとついついforループ回しがち。
ベクトル表記して内積表現すればOctaveが好きなカタチで処理してくれるんで速いよという話。
Highly optimized な linear algebraのライブラリが内部的に呼ばれるのでウンタラカンタラ。


# バカのやること 
clear;

tmp = 0;
for j=0:n
    tmp = tmp + theta(j)*x(j);
end;

# Vectorization
theta' * x;







2014年8月26日火曜日

Machine Learning (Andrew Ng) @ Coursera その3

今回はOctave マンセーうぇえ~いって話。

機械学習やらパターン認識で、Java C++ Python numpy Rとか色々ありましたねぇ。
でもそれらって結構実装に時間食うよね?めんどいよね?PDCA回すの遅れるよね?

シリコンバレーではこういった問題にはとうの昔に気付いておりまして、
すぐにこういった言語で実装し始めるんじゃなくて、
まずはプロトタイピングとしてOctaveが使われておりまっせ。

まずクイックにPDCAを回す競争力の高い企業が集結したシリコンバレーでは、
アイディアの実証がサクッとできてカネがかからんやつがプロトタイピングとして好まれたわけか。

ちなみに、Matlabでもいいんだけどクソたけーよって話もある。
あと、Python numpyでもいいけど、構文ちょっとややこしいやんけ。

とかいう感じで他の言語を軽くディスった上で、今日はOctaveの素晴らしさを布教しようじゃありませんか。



以下、コマンドメモり散らし!


変数の取り扱い

>>1 ~= 2
ans =  1
>>1 && 0
ans = 0
>>1 || 0
ans =  1
>>xor(1,0)
ans =  1
>>1 == 1
ans =  1
>>1 == 1 % this is a comment
ans =  1

>> PS1(">>>") % prompt would be changed to >>>

>>a = 3; % semicolon suppressing input
>>b = "hi";
>>a = pi
a =  3.1416
>>disp(sprintf("2 dicimals: %0.2f", a))
2 dicimals: 3.14
>>

>>format long
>>a
a =  3.14159265358979


行列の基礎的な取り扱い

>>A = [1 2;3 4; 5 6]
A =

   1   2
   3   4
   5   6

>>v = [1 2 3]
v =

   1   2   3

>>v'
ans =

   1
   2
   3

>>t = 1:0.1:2
t =

 Columns 1 through 3:

    1.00000000000000    1.10000000000000    1.20000000000000

 Columns 4 through 6:

    1.30000000000000    1.40000000000000    1.50000000000000

 Columns 7 through 9:

    1.60000000000000    1.70000000000000    1.80000000000000

 Columns 10 and 11:

    1.90000000000000    2.00000000000000

>>v = 1:6
v =

   1   2   3   4   5   6

>>ones(2,3)
ans =

   1   1   1
   1   1   1

>>zeros(1,)
parse error:

  syntax error

>>> zeros(1,)
            ^

>>zeros(1,3)
ans =

   0   0   0

>>eye(4)
ans =

Diagonal Matrix

   1   0   0   0
   0   1   0   0
   0   0   1   0
   0   0   0   1

>> help eye


乱数

>>rand(1,3) % uniform distribution
ans =

   0.740132599360654   0.343361310231155   0.212358308455146

>>randn(3,3) % standard normal distribution
ans =

   0.2927837134905641  -0.4591692991645791   1.0210607888876386
   1.2940773643349077   1.7832798099665554   0.0756273894367232
   0.7627828860428808  -0.7073869504487188  -0.3855058772989866

>> w = -6 + sqrt(10)*(randn(1,1000));
>>hist(w)
>>

ヒストグラムのプロットがこれだけでできるとか幸せか!!




これだけでbin数増やせるとかどんだけ今に生きた我々は幸せか!!
>>hist(w, 50) % add bins



サイズの扱い

>>A
A =

   1   2
   3   4
   5   6

>>size(A)
ans =

   3   2

>>sz = size(A)
sz =

   3   2

>>size(sz)
ans =

   1   2

>>size(A,2)
ans =  2
>>x = [1 2 3 4]
x =

   1   2   3   4

>>length(x)
ans =  4
>>length(A) % returns longer dimention
ans =  3


Unixコマンドもサポートしているよという話

>>pwd
ans = C:\Octave\3.2.4_gcc-4.4.0\bin
>>ls
>> load("file.dat")

>>who
Variables in the current scope:

A    a    ans  b    sz   t    v    w    x

>>whos
Variables in the current scope:

  Attr Name        Size                     Bytes  Class
  ==== ====        ====                     =====  =====
       A           3x2                         48  double
       a           1x1                          8  double
       ans         1x29                        29  char
       b           1x2                          2  char
       sz          1x2                         16  double
       t           1x11                        24  double
       v           1x6                         24  double
       w           1x1000                    8000  double
       x           1x4                         32  double

Total is 1061 elements using 8183 bytes

>>clear
>>whos

>>x = randn(100,2)
>>whos
Variables in the current scope:

  Attr Name        Size                     Bytes  Class
  ==== ====        ====                     =====  =====
       ans         1x14                        14  char
       x         100x2                       1600  double

Total is 214 elements using 1614 bytes


ファイル読み書き

>>save hello.mat x;
>>clear
>>load hello.mat
>>whos
Variables in the current scope:

  Attr Name        Size                     Bytes  Class
  ==== ====        ====                     =====  =====
       x         100x2                       1600  double

Total is 200 elements using 1600 bytes

>>save hello.txt x -ascii % save as text (ASCII)
>>


行列の操作

>>A = [1 2; 3 4; 5 6]
A =

   1   2
   3   4
   5   6

>>A(3,2)
ans =  6

>>A(2,:)  % ":" means every element along that row/column
ans =

   3   4

>>A([1 3], :)
ans =

   1   2
   5   6

>>
>>A(:,2) = [10; 11; 12]
A =

    1   10
    3   11
    5   12

>>A = [A, [100;101;102]]  % append another column vector to right
A =

     1    10   100
     3    11   101
     5    12   102

>>A(:) % put all elements of A into a single vector
ans =

     1
     3
     5
    10
    11
    12
   100
   101
   102

>>A
A =

     1    10   100
     3    11   101
     5    12   102

>>B = [7;8;9]
B =

   7
   8
   9

>>C = [A B]
C =

     1    10   100     7
     3    11   101     8
     5    12   102     9

2014年8月25日月曜日

Machine Learning (Andrew Ng) @ Coursera その2


第二回目の Machine Learning by Andrew Ng氏

今回は、線形回帰問題の解法として、最急降下法と正規方程式があるけど、
それらの特性について理解しようぜという話が主。


Feature scaling

最急降下法の収束スピードは各軸の値のスケールが近い方が速い。
スケールが揃っていないと、最急降下法における微分値が大きくなるケースが増えて(?)、
収束が遅くなる。
歪んだ楕円形を解消するため、各軸の数値をスケーリングすると収束特性が向上する。
この辺の数理的な背景については言及しないが、図的には納得の行く話。


覚えること:
 フィーチャーを同じ範囲に入るようにスケーリングすることで早く最急降下法が収束する。
 ( ⇔ より少ないイタレーション回数で収束する)

フィーチャースケーリングの一つとしては、Mean normalizationが便利
平均値で引いて、標準偏差でスケーリングするいわゆる標準化と呼ばれるよく知られた手法。


Gradient Descent in Practice Ⅱ

最急降下法が正しく動作していることのデバッギング方法は、
イタレーション回数を横軸とし、コスト関数の値をプロットすること。
コスト関数が凸で、ステップ長が十分小さければ単調減少するはず。

自動収束判定を行うには閾値を設定する必要があるけど、
それの決定は非常に難しい。
だから、割とコスト関数をプロットして大体の収束判定をグラフィカルに判断することも実務上はよくあること。

コスト関数が収束しないなーと思ったら、
単純に実装ミスか、イタレーションのパラメータ(ステップサイズ)が大きすぎるかを疑ったらよさげです。

収束には向かってるんだけど、コスト関数の収束が遅すぎるなぁと思った時は

こういうのも、図的なイメージが頭のなかに入っていれば、
コスト関数の挙動を見つつ何が原因かを相応できるんじゃないでしょうか。

Normal Equation

正規方程式の話は数学的な話はすっ飛ばして、
データが困難だったらこんな行列Xと教師セットから行列X,ベクトルyを当てはめて

pinv(X'*X)*X'*y すればおk

って感じでした。
ちなみに最急降下法では教師セットの各入力変数のスケールが合ってなかったら揃えてたわけだけど、
正規方程式使う場合は別に微分してイタレーションしてるわけじゃないので、必要なし。


理解すべきことは最急降下法と正規方程式の長所短所。

最急降下法は、
ステップサイズ選択面倒
イタレーションも面倒
でも、特徴数が大きくても問題なく動作する

正規方程式は、
ステップサイズの選択いらない
イタレーションいらない
ただし、逆行列の計算は次元が大きい時は、行列演算の負荷がクソ上がる
(逆行列の演算は O(n^3) オーダーで増加する)

ざっくりまとめると、
特徴数が大きい時は最急降下法使おうね、
小さい時は正規方程式が強いお。
大体特徴数が10^6程度を境界として使い分けましょう。
アルゴリズム・問題・フィーチャー数に応じて考えて使い分けられる人間になりましょ。

ということです。


Normal Equation Noninvertibility

正規方程式は逆行列計算してるけど、非正則行列とかどないすんのって議論。
至極もっともな話ですが、 (X'*X) が非正則になることなんて超まれなのですよという話。

Octaveさんはその辺しっかりやってくれちゃってる。
逆行列を計算する関数は pinv()と inv()があるんだけど、
pinv() は擬似逆行列を計算してくれてる p ぱ pseudo(擬似)の p です。

X'X は、なぜ非正則行列になることがまれと言い切れるのか。
起きる原因は

1.学習データが冗長な時。
  一次結合の関係性があるときに起きる 
  => 冗長なら削除すればこの問題は解決する。あるいは主成分分析でもすれやという話。

2.フィーチャー数が教師セット数よりも圧倒的に多いとき
  フィーチャー削れや、それか正規化せぇや
  という話。
  というか教師セットが少ない時にパラメータ数を増やす意味があまりない。

上記2つの問題は解決可能なので、学習問題をとく時はめったに非正則になりません。
気にせずpinv()使っていいです安心して下さい。


Machine Learning (Andrew Ng) @ Coursera その1

Machine Learning
by Andrew Ng

Machine Learning by Andrew Ng =>  https://class.coursera.org/ml-006


Coursera上に転がっている、Stanford大学のAndrew Ng先生の、
Linear Regressionの講義がこれまでに無いわかり易さで感動した。

線形回帰を説明するのに、多変数関数のベクトル微分や凸関数の理解が、
きちんとした理解のためには必要なわけだけど、

- 変数を絞る
- 具体的なデータをプロットして図的に説明する
- 凸関数・偏微分などの細かい事項はスキップ

といった気遣いのお陰で、回帰という問題を万人に(高校生レベルでも)わかるように説明されていた。

おそらく線形回帰の説明を日本の大学で受講すると私の経験上、
偏微分だー凸関数だー行列演算だー
が始まって本質と違う部分で挫折する人間(私)が量産されているはずなんですよ。

できるだけシンプルに、平易な言葉で説明することって
本質が何かを把握した人間にできる所業なのだとひしひしと感じた。



加えて、

基本的には線形回帰は正規方程式で数値的に陽に解けるわけだけど、
最急降下法でのイタレーション処理は、比較的大きなデータセットにおいてはスケールする点にも言及されていたり

講義の冒頭で、
シリコンバレーのエンジニアはOctaveを使ってサクッとプロトタイピングしてから、
C++等の静的型付け言語で書きなおしているとの話もあったり


で最高のコンテンツだと思いました。



話は変わるが、


MOOCとよばれるオンラインの教育コンテンツがこれほど良質だとは思わなかったので驚愕している。
おそらく普通に東大京大通うより効率いい気がしてる。
# 東大通ったこと無いけど。


気になってGoogle trendsでMOOCの主要どころのサービスを検索したところ、
インド・シンガポール・アメリカといったIT + 英語が強い国で人気っぽい。
残念ながら日本がない。。。
今の日本の大学生にもっと広まれば、自分とは比較にならんくらい賢い学生が量産されるのではなかろうか。
逆に、こういった流れに乗れなければIT分野でますます突き放されるのではなかろうか。


ちなみに最近日本語の字幕が出るようになったので、
英語非対応の脳味噌をお持ちの方でもCoursera使えるよ!(多分一部の講義に限る?)
私は頑張る。あなたも頑張る。



2014年8月20日水曜日

dotinstall:: Ruby on Rails4 のメモ

#05 タスク管理アプリを作ってみよう

  390  rails new taskapp --skip-bundle

一度インストールしたgemのskip

  391  cd taskapp/
  392  emacs Gemfile

therubyracerのコメントアウトを消す。
gem 'io-console' を追記する

  393  rails s

サーバー起動させて動作確認

  396  rails g model Project title

モデル生成。
頭文字は大文字、単数形。

  397  rake db:migrate

DBに反映させる

#06 rails db/rails consoleを使おう

  398  rails db

sqliteのインタラクティブシェル開く

  399  rails console

irb開く

#07 Controllerを作ってみよう

  401  rails g controller Projects

コントローラ生成

  403  emacs config/routes.rb

ルーティングの編集。
resources :projects を追記

  404  rake routes

ルーティングの確認



  407  emacs app/controllers/projects_controller.rb

こんなの作る
class ProjectsController < ApplicationController
  def index
    @projects = Project.all
  end
end

  408  touch app/views/projects/index.html.erb
  409  emacs app/views/projects/index.html.erb

こんなの作る

<h1>Projects</h1>
<ul>
  <% @projects.each do |project| %>
  <li> <%= project.title %> </li>
  <% end %>
</ul>
  410  rails s


  416  emacs config/routes.rb

root 'projects#index' を追記



  420  emacs app/views/layouts/application.html.erb

image_tagを追記

<!DOCTYPE html>
<html>
<head>
  <title>Taskapp</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>
<%= image_tag "logo.png" %>
<%= yield %>
</body>
</html>
  421  cd app/assets/images/
  422  wget http://cdn.appgiga.jp/files/2012/04/0e9fb148b4f53059c459b0839ee286f71.png
  423  ls
  424  mv 0e9fb148b4f53059c459b0839ee286f71.png logo.png

"logo.png"を適当に拾ってきて app/assets/images/に置く

  429  emacs app/assets/stylesheets/application.css
プロジェクト全体のcssファイル編集してみる。


  433  emacs app/views/layouts/application.html.erb

yield はクラス内の関数で吐かれるデータ。
<%= yield %>

projects_path は、rake routes でPrefix表示される文字列_pathとすれば、URI Patternに変換してくれることの確認。
<%= link_to "Home", "/" %>
<%= link_to "Home", projects_path %>

#11 Projectsの詳細を表示しよう

  446  emacs app/views/projects/index.html.erb

<h1>Projects</h1>
<ul>
  <% @projects.each do |project| %>
  <li> <%= link_to project.title, project_path(project.id) %> </li>
  <% end %>
</ul>
  450  emacs app/controllers/projects_controller.rb

showの振る舞いを追記。
paramsはURLから取れるデータ。idはDB上のメンバの番号?
class ProjectsController < ApplicationController
  def index
    @projects = Project.all
  end
  def show
    @project = Project.find(params[:id])
  end
end
  451  cp  app/views/projects/index.html.erb app/views/projects/show.html.erb
  453  emacs app/views/projects/show.html.erb

showのviewを生成。とりあえずコピーして編集。表示だけ。
<h1><%= @project.title %></h1>
#12 新規作成フォームを作ろう

  455  emacs app/controllers/projects_controller.rb

newの関数を実装。
  def new
    @project = Project.new
  end
  457  emacs app/views/projects/index.html.erb

<%= link_to "Add New", new_project_path %>
を追加して /projects/new へのリンクを作成。

  459  cp app/views/projects/index.html.erb app/views/projects/new.html.erb
  460  emacs app/views/projects/new.html.erb

newのviewを作成。
<h1>Add New<h1>
<%= form_for @project do |f| %>
<p>
  <%= f.label :title %><br>
  <%= f.text_field :title %>
</p>
<p>
  <%= f.submit %>
</p>
<% end %>

#13 データを保存してみよう

  463  emacs app/controllers/projects_controller.rb

create関数の定義。
外部からの入力はサニタイズするため(?) params に一旦permitをかませる。
class ProjectsController < ApplicationController
  def index
    @projects = Project.all
  end
  def show
    @project = Project.find(params[:id])
  end
  def new
    @project = Project.new
  end
  def create
    @project = Project.new(project_params)
    @project.save
    redirect_to projects_path
  end
  private
    def project_params
      params[:project].permit(:title)
    end
end


今日もRails作業メモ


Ruby on Railsで簡単なブログアプリを作成。

 $ rails new sample_app_0819
   # Projectを作成
 $ cd sample_app_0819/

 $ emacs Gemfile 
   # gem 'therubyracer' 部分のコメントアウトを削除して gem 'io-console' 追加

 $ bundle exec rails g scaffold book title:string memo:text
   # scaffoldでbook作成
 $ bundle exec rake db:migrate
   # データベースに反映
 $ bundle exec rails s
   # サーバー起動










2014年8月19日火曜日

クソな仕事を量産するエンジニアはマジで要らない子。


「開発が苦労してることなんてお客さんこれっぽっちも理解しないから、
ユーザーが求める価値を提供できなかったらそのエンジニアの仕事はクソだよ」




つっけんどんな言い方。





だけど響いた。




脳に、刺さった。




いつもこういうものの言い方をする先輩がいる。


言われた時はもうまじでガッペむかつく!!



3分言われた意味を冷静に考える。



反論のロジックを練る。




練る。



練る。



。。。なんも出てこない。



論理的に正しい。



はい、私がクソだ。









結局は実装とコストのトレードオフなんだけど、


エンジニアがマジで極限にギークだったら、


どれもこれもコストゼロに漸近して、



一瞬で価値提供できて、


会社ガッポガッポ。












付加価値が出せていない。



下位レイヤのせい、システムアーキテクチャのせい。


そんなエンジニア、まじで要らいない子。





結論!!




頑張ろう。



批判の中に、建設的な意見を入れよう。



いつも語尾は「できる」にしよう。

Ruby on RailsをEC2上で実行してみるの巻

動作環境の確認

blogアプリをGithubからcloneして鯖立てしてみる。
http://iti.hatenablog.jp/entry/2014/05/20/163244
記述通り実行したらちゃんとEC2上で動作しました。
実行環境が問題ないことがわかって安心。

スクラッチからRails

次に、スクラッチからRailsを実行してみたら以下のエラー発生。

$ bundle exec rails g scaffold book title:string memo:text
/home/ec2-user/.gem/ruby/2.0/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:247:in `require': cannot load such file -- io/console (LoadError)

このエラーが出た時は、

gem install io-console
してGemfileに
gem 'io-console'
を追記すれば良い。

参考URL:
http://stackoverflow.com/questions/23184819/rails-new-app-or-rails-h-craps-out-with-cannot-load-such-file-io-console

2014年8月14日木曜日

Scrapyでスクレイピングする話@ Pytexas2013


スクレイピングをPythonでやるのに、
urllib2とかrequestとかbeautifulsoup組み合わせて実装するの面倒ですよね。
スクレイピーはそういったタスクを全部やってくれて、おまけにクローリングのスケジューリングとかもできてしまうフレームワークがあります、それがScrapy。

Githubに講演者がGithubにレポジトリあげてくれていた。
https://github.com/dmclain/scrapy-pytexas-2013




/spiders/talkspider_basic - parse a single page and yield a series of items

単純に1ページをスクレイプするscrapyのデモ。

PytexasItemは収集する要素のクラス。
データモデルを定義しています。

class PytexasItem(Item):
# define the fields for your item here like:
# name = Field()
title = Field()
time = Field()
speaker = Field()
description = Field()



TalkspiderBasicSpiderはクロールする際のスパイダーを実装します。
name, allowed_domains, start_url はクラスの要素で、
その名の通りスパイダーがクロールするドメインとかURLを指定します。
name is used for internally keeping track of なので内部的に利用されるクラスの要素です。



class TalkspiderBasicSpider(BaseSpider):
name = "talkspider_basic"
allowed_domains = ["www2.pytexas.org"]
start_urls = ['http://www.pytexas.org/2013/schedule/']
def parse(self, response):
hxs = HtmlXPathSelector(response)
dls = hxs.select('///dl')
for dl in dls:
times = dl.select('dt/text()').extract()
titles = dl.select('dd/a/text()').extract()
for time, title in zip(times, titles):
title = title.strip()
yield PytexasItem(title=title, time=time)



HtmlXPathSelector()で選択したHTMLのDOMを解析してXPath表記の要素をextractします。




scrapyはデフォルトではstart_urlに書かれたサイト全体をクロールする。
スパイダーのコンストラクタが呼ばれるとクロールするタスクをキューに貯める。
全部クロールするのは面倒ですし無駄が多いので、クロールするURLを指定したいところ。
そこで出てくるのがTalkspiderCrawlSpider()



(15:00くらいから~)
「XPathなんぞ」という方は、Google Chromeをお使い下さい。
XPathが知りたい部分をカーソルで選択して右クリック。
「要素を検証 or Inspect Element」 選択するとDeveloper Toolが下に表示されます。
Chrome上で、 「 Ctrl+Shift+i 」するとDeveloperToolが表示されるアレです。
Developer Consoleに出てる項目を右クリックしてCopy XPathすればよいです。
とても快適です。



(20:00くらいから)


def parse(self, response):
hxs = HtmlXPathSelector(response)
dls = hxs.select('///dl')
for dl in dls:
times = dl.select('dt/text()').extract()
titles = dl.select('dd/a/text()').extract()
hrefs = dl.select('dd/a/@href').extract()
for time, title, href in zip(times, titles, hrefs):
title = title.strip()
yield Request(
url=''.join(('http://www.pytexas.org', href)),
callback=self.parse_item,
meta={'time': time, 'title': title}
)


yield時にitem返すんじゃなくてrequestを返してるのがポイント。


- Being Good citizen
  スクレイプするときはrobot.txtに従いましょうね、ダウンロードにはディレイを入れて負荷かけ内容にしましょうね



Ruby on Rails 入門 その1: 簡単なアプリを作成してみる

1. myapp プロジェクトを作成

$ rails new myapp
DL is deprecated, please use Fiddle
      create
      create  README.rdoc
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/assets/javascripts/application.js
      create  app/assets/stylesheets/application.css
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/views/layouts/application.html.erb
      create  app/assets/images/.keep
      create  app/mailers/.keep
      create  app/models/.keep
      create  app/controllers/concerns/.keep
      create  app/models/concerns/.keep
      create  bin
      create  bin/bundle
      create  bin/rails
      create  bin/rake
      create  config
      create  config/routes.rb
      create  config/application.rb
      create  config/environment.rb
      create  config/secrets.yml
      create  config/environments
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/initializers
      create  config/initializers/assets.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/cookies_serializer.rb
      create  config/initializers/filter_parameter_logging.rb
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/initializers/session_store.rb
      create  config/initializers/wrap_parameters.rb
      create  config/locales
      create  config/locales/en.yml
      create  config/boot.rb
      create  config/database.yml
      create  db
      create  db/seeds.rb
      create  lib
      create  lib/tasks
      create  lib/tasks/.keep
      create  lib/assets
      create  lib/assets/.keep
      create  log
      create  log/.keep
      create  public
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/favicon.ico
      create  public/robots.txt
      create  test/fixtures
      create  test/fixtures/.keep
      create  test/controllers
      create  test/controllers/.keep
      create  test/mailers
      create  test/mailers/.keep
      create  test/models
      create  test/models/.keep
      create  test/helpers
      create  test/helpers/.keep
      create  test/integration
      create  test/integration/.keep
      create  test/test_helper.rb
      create  tmp/cache
      create  tmp/cache/assets
      create  vendor/assets/javascripts
      create  vendor/assets/javascripts/.keep
      create  vendor/assets/stylesheets
      create  vendor/assets/stylesheets/.keep
         run  bundle install
DL is deprecated, please use Fiddle
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
Using rake 10.3.2
Using i18n 0.6.11
Using json 1.8.1
Using minitest 5.4.0
Using thread_safe 0.3.4
Using tzinfo 1.2.2
Using activesupport 4.1.4
Using builder 3.2.2
Using erubis 2.7.0
Using actionview 4.1.4
Using rack 1.5.2
Using rack-test 0.6.2
Using actionpack 4.1.4
Using mime-types 1.25.1
Using polyglot 0.3.5
Using treetop 1.4.15
Using mail 2.5.4
Using actionmailer 4.1.4
Using activemodel 4.1.4
Using arel 5.0.1.20140414130214
Using activerecord 4.1.4
Using bundler 1.6.5
Using coffee-script-source 1.7.1
Using execjs 2.2.1
Using coffee-script 2.3.0
Using thor 0.19.1
Using railties 4.1.4
Using coffee-rails 4.0.1
Using hike 1.2.3
Using multi_json 1.10.1
Using jbuilder 2.1.3
Using jquery-rails 3.1.1
Using tilt 1.4.1
Using sprockets 2.11.0
Using sprockets-rails 2.1.3
Using rails 4.1.4
Using rdoc 4.1.1
Using sass 3.2.19
Using sass-rails 4.0.3
Using sdoc 0.4.1
Using sqlite3 1.3.9
Using turbolinks 2.2.2
Using uglifier 2.5.3
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.

2. サーバー起動

$ cd myapp/; rails s
C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/data_source.rb:182:in `rescue in create_default_data_source': No source of timezone data could be found. (TZInfo::DataSourceNotFound)
Please refer to http://tzinfo.github.io/datasourcenotfound for help resolving this error.
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/data_source.rb:179:in `create_default_data_source'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/data_source.rb:40:in `block in get'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/data_source.rb:39:in `synchronize'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/data_source.rb:39:in `get'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/timezone.rb:629:in `data_source'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/timezone.rb:92:in `get'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/timezone_proxy.rb:67:in `real_timezone'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/timezone_proxy.rb:30:in `period_for_utc'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/tzinfo-1.2.2/lib/tzinfo/timezone.rb:549:in `current_period'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/core_ext/object/try.rb:45:in `public_send'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/core_ext/object/try.rb:45:in `try'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/values/time_zone.rb:223:in `utc_offset'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/values/time_zone.rb:396:in `block in []'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/values/time_zone.rb:396:in `tap'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/values/time_zone.rb:396:in `[]'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/core_ext/time/zones.rb:60:in `find_zone!'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/railtie.rb:20:in `block in <class:Railtie>'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/initializable.rb:30:in `instance_exec'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/initializable.rb:30:in `run'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/initializable.rb:55:in `block in run_initializers'
        from C:/Ruby200-x64/lib/ruby/2.0.0/tsort.rb:150:in `block in tsort_each'
        from C:/Ruby200-x64/lib/ruby/2.0.0/tsort.rb:183:in `block (2 levels) in each_strongly_connected_component'
        from C:/Ruby200-x64/lib/ruby/2.0.0/tsort.rb:219:in `each_strongly_connected_component_from'
        from C:/Ruby200-x64/lib/ruby/2.0.0/tsort.rb:182:in `block in each_strongly_connected_component'
        from C:/Ruby200-x64/lib/ruby/2.0.0/tsort.rb:180:in `each'
        from C:/Ruby200-x64/lib/ruby/2.0.0/tsort.rb:180:in `each_strongly_connected_component'
        from C:/Ruby200-x64/lib/ruby/2.0.0/tsort.rb:148:in `tsort_each'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/initializable.rb:54:in `run_initializers'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/application.rb:300:in `initialize!'
        from C:/home/myapp/config/environment.rb:5:in `<top (required)>'
        from C:/home/myapp/config.ru:3:in `require'
        from C:/home/myapp/config.ru:3:in `block in <main>'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/builder.rb:55:in `instance_eval'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/builder.rb:55:in `initialize'
        from C:/home/myapp/config.ru:in `new'
        from C:/home/myapp/config.ru:in `<main>'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/builder.rb:49:in `eval'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/builder.rb:49:in `new_from_string'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/builder.rb:40:in `parse_file'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/server.rb:277:in `build_app_and_options_from_config'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/server.rb:199:in `app'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands/server.rb:50:in `app'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rack-1.5.2/lib/rack/server.rb:314:in `wrapped_app'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands/server.rb:130:in `log_to_stdout'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands/server.rb:67:in `start'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands/commands_tasks.rb:81:in `block in server'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands/commands_tasks.rb:76:in `tap'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands/commands_tasks.rb:76:in `server'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
        from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.1.4/lib/rails/commands.rb:17:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'
=> Booting WEBrick
=> Rails 4.1.4 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
Exiting

エラーの内容は "tzinfo-data" が無いよということなので、
既知の不具合を修正するためGemfileの以下の箇所を修正。

[修正前] gem 'tzinfo-data', platforms: [:mingw, :mswin]
[修正後] gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw]

3. tzinfo-data入れつつbundle updateする

gem install tzinfo-data && bundle update


4. サーバー起動

$ rails s
[2014-08-14 01:10:15] INFO  WEBrick 1.3.1
[2014-08-14 01:10:15] INFO  ruby 2.0.0 (2014-05-08) [x64-mingw32]
[2014-08-14 01:10:15] INFO  WEBrick::HTTPServer#start: pid=2216 port=3000
WEBrickサーバーが起動し、port3000でアプリが起動しました。
http://localhost:3000/ にウェブブラウザからアクセスしてアプリが起動していることを確認。

今後は app, config, db フォルダ以下を編集していきます。





5. Scaffold をつかって管理したいデータを指定して生成する


$ rails generate scaffold User name:string score:integer
DL is deprecated, please use Fiddle
      invoke  active_record
      create    db/migrate/20140814001440_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      create        test/helpers/users_helper_test.rb
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.js.coffee
      invoke    scss
      create      app/assets/stylesheets/users.css.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.css.scss
Viewとかコントローラとか作成される。
マイグレーションファイルも作成されてます。
> db/migrate/20140814001440_create_users.rb


6. マイグレーションファイルの内容をデータベースに反映

$ rake db:migrate
== 20140814001440 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0020s
== 20140814001440 CreateUsers: migrated (0.0030s) =============================

このあとアプリを起動するとユーザー管理画面にアクセスできるようになっています。
http://localhost:3000/users



$ rails s
[2014-08-14 01:10:15] INFO  WEBrick 1.3.1
[2014-08-14 01:10:15] INFO  ruby 2.0.0 (2014-05-08) [x64-mingw32]
[2014-08-14 01:10:15] INFO  WEBrick::HTTPServer#start: pid=2216 port=3000

$ rails s
[2014-08-14 01:10:15] INFO  WEBrick 1.3.1
[2014-08-14 01:10:15] INFO  ruby 2.0.0 (2014-05-08) [x64-mingw32]
[2014-08-14 01:10:15] INFO  WEBrick::HTTPServer#start: pid=2216 port=3000

$ rails s
[2014-08-14 01:10:15] INFO  WEBrick 1.3.1
[2014-08-14 01:10:15] INFO  ruby 2.0.0 (2014-05-08) [x64-mingw32]
[2014-08-14 01:10:15] INFO  WEBrick::HTTPServer#start: pid=2216 port=3000