barutanGNE's blog

kindleで読んだ本の感想や、プログラミングに関する記事など。

HaskellとPythonで階差数列

Haskell

Prelude> let diff ls = zipWith (-) (tail ls) ls
Prelude> diff [1,2,3,4,5]
[1,1,1,1]
Prelude> diff [x^2 + x -1 | x <- [0..10]]
[2,4,6,8,10,12,14,16,18,20]

Python

>>> f = lambda a, b: a-b
>>> diff = lambda ls: map(f, ls[1:], ls)
>>> ls1 = diff([1,2,3,4,5])
>>> list(ls1)
[1, 1, 1, 1]
>>> ls2 = diff([x*x + x -1 for x in range(11)])
>>> list(ls2)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

応用で、数列が単調増加(減少)しているか、とかも割りと簡潔に書ける。

で、そういえば、階差数列っていつ役に立つの?

PythonのmapはHaskellのzipWith?

Pythonでmapを使う

>>> f1 = lambda x: x * 2
>>> ls1 = map(f1, range(10))
>>> list(ls1)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> f2 = lambda x, y: x*2 + y*2
>>> ls2 = map(f2, range(10), range(10))
>>> list(ls2)
[0, 4, 8, 12, 16, 20, 24, 28, 32, 36]
>>> f3 = lambda x, y, z: x*2 + y*2 + z*2
>>> ls3 = map(f3, range(10), range(10), range(10))
>>> list(ls3)
[0, 6, 12, 18, 24, 30, 36, 42, 48, 54]

Python3.3では、mapはイテレータを返すので、結果の全体を見たいときはlistをかけてやる必要がある。

1引数の関数でmapするときには、Haskellと変わらない。しかし、Pythonのmapは可変引数で、2引数の関数をmapしたり、3引数の関数をmapしたりできる。これらは、HaskellではzipWithやzipWith3になる。

同じことをHaskellでやる

Prelude> let f1 = \x -> x*2
Prelude> map f1 [0..9]
[0,2,4,6,8,10,12,14,16,18]
Prelude> let f2 = \x y -> x*2 + y*2
Prelude> zipWith f2 [0..9] [0..9]
[0,4,8,12,16,20,24,28,32,36]
Prelude> let f3 = \x y z-> x*2 + y*2 + z*2
Prelude> zipWith3 f3 [0..9] [0..9] [0..9]
[0,6,12,18,24,30,36,42,48,54]

インタプリタでの実行をそのまま貼り付けているので、letとかPreludeが邪魔なのはごめんなさい。

言われてみると、zipWithをzipWith2と思ってみると、mapってzipWith1と思える関数だな。

他の言語でのmapやzipWithはMap(Wikipedia))に載っている。

Pythonのdatetimeで遊んでみる(Python3.3)

昨日今日は、データベーススペシャリスト勉強そっちのけでCheckiOで遊んでいた。やっとレベル8になった。Pythonのdatetimeモジュールが便利だったので、自分用メモ。timedeltaオブジェクト同士での演算が面白い。

参考

公式リファレンス

モジュールをインポートする

import datetime from *

timedeltaオブジェクトとは?

datetime間の差分を表すオブジェクト。datetime - datetimeをした時に作成される。

datetimeで、引き算ができる、っていうのが面白い。ちなみに、足し算はできない。

実行結果は以下のようになる

now: 2014-02-16T20:55:49.571721
24839 days, 20:55:49.571721
days: 24839
seconds: 75349
microseconds: 571721

timedeltaオブジェクトの演算

もっと面白いのは、timedelta同士で割り算や剰余をとれること。timedelta * int やtimedelta / intもできる。

実行結果は以下のようになる。

[5 year]: 1825 days, 0:00:00
[1/3 year]: 121 days, 16:00:00
[1 week]: 7 days, 0:00:00
[year / week]: 52.142857142857146
[year // week]: 52
[year % week]: 1 day, 0:00:00

余談

どうしてPython3.xではreduceが組み込み関数からはずされちゃったの?????

データベーススペシャリストの勉強のために

(2/14 大学の講義資料等をちょっと追記)

平成26年度春の試験に挑戦予定なので、参考サイト等をまとめてみる。

自分の進捗状況

自分は学生なので、実務でDB触ってない。設計どころかSQLも普段は使ってなかった。

ひと通り参考書を読んで、だいたい午前2問題は解けるように。午後問題は、E-R図を書くのにまだ慣れていない。問題文の量が多くて、まとまった時間を設けないと挑戦すらできないのがつらい。

午前1も免除にならないので、これから対策しないと。

参考書

徹底攻略 データベーススペシャリスト教科書 平成26年度 (ITプロ/ITエンジニアのための徹底攻略 Tettei Kouryak)

徹底攻略 データベーススペシャリスト教科書 平成26年度 (ITプロ/ITエンジニアのための徹底攻略 Tettei Kouryak)

買った当時、kindleで読めるのがこれくらいしかなかったから、くらいの理由で選んだ。でも説明が非常に丁寧で読みやすい。他の参考書は読んでないから、比較はできないけど。

参考動画

試験の傾向と対策


データベーススペシャリスト試験 とは 2014年春 - YouTube

上で紹介した書籍の出版元の、「わくわくスタディワールド」から公開されている動画。データベーススペシャリストの出題傾向や問題選択の基本方針などを説明してくれている。

午前問題解説

データベーススペシャリスト 午前 YouTube 解説映像

同じく、「わくわくスタディワールド」から。一問につき3分くらいで解説してくれている。特に、平成21年度の試験については、全問解説が用意されている。

Webラーニングプラザ

下は、アルゴリズムとデータ構造コースの動画だが、B木が説明されているので紹介。

Webラーニングプラザの動画は、基本、応用を勉強するときに非常に良かった。

Coursera

Introduction to Databases

Courseraにも、DBの講座あり。全て英語。はい、全く活用していません。

参考サイト

大学の講義資料等

正規化理論などは、いっそ大学の講義資料などを読みながらしっかり勉強したほうが、理解が早いのではないだろうか。といいつつ、自分はまだ第四正規形、第五正規形は怪しい。

個人的には、一番上(早稲田大学)の講義資料が、高次の正規形を理解するのに一番わかりやすかった。

SQL対策

SQLは、MySQLで勉強した。実際、手を動かしてみたほうが、習得は早いと思う。

w3cSQLチュートリアル。ブラウザでSQLの演習問題をとくことができる。操作対象の表も用意されていて、非常に良いサイトだと思うのだけれど、英語なのであまり活用できてない。

午前問題対策のWeb問題集

データベーススペシャリスト午前1,2の問題もまとめられていて、簡単な解説も用意されている。

Webで午前問題に挑戦できる。選択肢を選んで、正誤判定してくれるが、問題の解説はない。

ブログなど

-リレーショナル・データベースの世界

-漢(オトコ)のコンピュータ道

どちらも丁寧な解説記事がいっぱい。

午後問題対策

まだしてない。なんか本買わないとだめかなぁ。

Twitter Streaming API、Node.js、MySQLでツイートの言語を調べてみたら、インドネシアすごかった

Twitter Streaming API からのツイートをMySQLに保存

SQLを勉強中なんだけど、なにか意味のあるデータを持っていないと、いろいろな問い合わせを勉強していてもおもしろくない。というわけで、Twitter Streaming APIから流れてくるツイートをMySQLに突っ込むプログラムをNode.jsを書いてみた。

ただ、肝心のツイート内容やユーザー名、ツイートの日付などなどを突っ込もうと思うと、テキストのエスケープや日付の形式の変換が結構めんどう。そこで、とりあえずユーザーid、言語、フォロー数、フォロワー数だけ記録。

Twitter Streaming API からツイートを取得

ただ標準出力に結果を流し続けるだけだったら、以下のようなプログラムになる。

Node.jsでMySQL

node-mysqlを使うと、以下のようにしてMySQLと接続できる。 使うデータベースは、あらかじめ作成して権限を設定しておく。

全体のソースコード

上2つを単純に組み合わせたシンプルなプログラムなので、とくに説明するところもなし。

実験結果

2014/2/4 火曜日の、17:00あたりから17:20くらいまで動かして、約5万ツイート取得。いろいろ分析するには、すごく偏ったデータ。ツイートの言語を調べるなら、時差の影響を考えても最低24時間は動かすべき。

しかしあんまりたくさんデータがあっても、複雑な問い合わせができなくなるので、今回はこれくらいで。

総数を数える

SQL

select count(*) from twitter_public;

結果

+----------+
| count(*) | 
+----------+
|    49361 |
+----------+

言語別に総数を数える

SQL

select lang, count(*) sum from twitter_public 
group by lang order by sum desc;

結果

+------+-------+
| lang | sum   |
+------+-------+
| ja   | 14694 |
| en   | 13088 |
| id   |  5204 |
| es   |  2959 |
| ar   |  2858 |
| tr   |  1677 |
| und  |  1423 |
| ru   |  1207 |
| ko   |  1114 |
| pt   |   999 |
| fr   |   723 |
| tl   |   652 |
| th   |   557 |
| it   |   334 |
| nl   |   325 |
| de   |   276 |
| vi   |   177 |
| pl   |   141 |
| et   |   133 |
| sl   |   129 |
| ht   |    92 |
| sv   |    89 |
| sk   |    74 |
| lv   |    72 |
| bg   |    58 |
| zh   |    46 |
| el   |    40 |
| da   |    37 |
| fa   |    36 |
| fi   |    32 |
| no   |    31 |
| hu   |    31 |
| he   |    26 |
| uk   |    25 |
| hi   |    22 |
| lt   |    18 |
| ur   |    11 |
| is   |    11 |
| bn   |     5 |
| ta   |     4 |
| ne   |     3 |
| my   |     1 |
| am   |     1 |
| si   |     1 |
| hy   |     1 |
+------+-------+

日本語(ja)ツイートが英語(en)より多くなってる。データをとった17時付近だと、ニューヨークあたりは午前3時、だからかな? 中国語(zh)は、金盾で少ないんだろう。

インドネシア????

(id)はインドネシア語、らしい

ネイティブスピーカーの数が多い言語の一覧 - Wikipedia

インドネシア語は、上を見ると37位なんだけどな……でも話し言葉と書き言葉でごにょごにょ……。とか思っていたら

なぜ君は、Facebookユーザー数世界トップの「インドネシア」を目指さないのか? ー VANGUARD定例イベント 3月30日開催【増田(@maskin)真樹】 : TechWave

そういえばこんな記事もあった

「投資有望国」首位はインドネシア、中国は4位転落 JBIC調査 - SankeiBiz(サンケイビズ)

人口世界第四位のインドネシア、今日まで場所もうろ覚えでごめんなさい。

Node.jsでTwitter API v1.1 を叩くには?

Node.jsで、TwitterAPIを叩こうと思ったら、結構苦労した。
まだ、納得できる解決策にたどり着いていない。

環境

node v0.10.24
2014年1月31日

Twitter API v1.1とは

2013年6月末に、Twitter APIがv1.0からv1.1に変更された。
Node.jsのTwitterモジュールはいくつかあるんだけど、ソースコードを見ると、いくつかのメソッド(あるいは大部分)がv1.1に未対応だったりして、完全にv1.1に対応しているモジュールを探すのに苦労している。
今回実験したのは、ntwitterとnode-twitterの2つのモジュールが中心だが、どちらもv1.1に完全には対応していない様子。他のモジュールも、ソースコードを見る限り、怪しいか対して便利じゃない。

たどり着いた暫定的な方法

まず結論。

  1. Streaming APIを使う分には、大抵どのモジュールでも問題ない。
  2. REST APIを使うときには、モジュールは
npm install twitter

がとりあえず結果が帰ってきた。

などのAPIv1.1に関するドキュメントを見ながら、

var util = require('util'),
    twitter = require('twitter');
var twit = new twitter({
    consumer_key: 'xxx',
    consumer_secret: 'xxx',
    access_token_key: 'xxx',
    access_token_secret: 'xxx'
});

twit.get('/search/tweets.json', {"q":"#Node"}, function(data) {
     console.log(data);

のように、地道にエンドポイントとオプションを指定してツイートを取得。

// twitterモジュールでは一応動く
twit.search('nodejs OR #node', function(data) {
     console.log(data);
});

のような便利な関数は、動かない場合が多い。

以下、具体的に自分が試したこと。

ntwitter

Node.jsでのTwitterモジュールとして、一番人気のよう。
https://nodejsmodules.org/tags/twitter
versionは0.5.0で試した。

Streaming APIは大丈夫

技術ブログなどでも、ntwitterを使った記事は多くて、たとえば以下の記事では、Socket.ioとexpress、ntwitterを使って、TwitterのStreaming APIからキーワードにマッチするツイートをリアルタイムで表示するWebアプリを作れる。
node.js + socket.ioでTwitterのStreaming APIを使ってみる - 大人になったら肺呼吸

ntwitterは、Streaming APIを利用するぶんには問題なくて、上記のWebアプリもちゃんと動かすことができた。

REST APIはだめ

AvianFlu/ntwitter · GitHub
ntwitterのgithubのページでは、以下の様なコードが紹介されている。

twit.search('nodejs OR #node', {}, function(err, data) {
  console.log(data);
});

しかし、このコードだとエラーが返される。
原因は、v1.1への以降による、searchのエンドポイント変更に未対応だから。
Githubでlib/keys.jsのソースを見ると、using1.1とは書いてあるのだが、search_baseで廃止されたエンドポイントにアクセスしている。
GET search | Twitter Developers
v1では、http://search.twitter.com
v1.1では、https://api.twitter.com/1.1/search/tweets.json

node-twitter

twitter-nodeやnode-twitterがあって紛らわしいんだけど、とにかく

npm install twitter

でインストールできるやつ。
Github
desmondmorris/node-twitter · GitHub

こっちだと、

twit.search('nodejs OR #node', {}, function(err, data) {
  console.log(data);
});

でちゃんと結果が帰ってきた。
しかし、用意されているメソッドでも、以下は結果が帰ってこない。

twit.getMentions(function(data) {
	console.log(data);
 });

結局、用意されている便利な関数には頼らないで、リファレンスを見ながら以下のようにAPIを叩くのが良さげ。

var util = require('util'),
    twitter = require('twitter');
var twit = new twitter({
    consumer_key: 'xxx',
    consumer_secret: 'xxx',
    access_token_key: 'xxx',
    access_token_secret: 'xxx'
});

//キーワードで検索
twit.get('/search/tweets.json', {"q":"#Node"}, function(data) {
    console.log(data);
});

//自分のツイート最新20件
twit.get('/statuses/user_timeline.json', {include_entities:true}, function(data) {
    console.log(util.inspect(data));
});

//タイムライン最新20件
twit.get('/statuses/home_timeline.json', {include_entities:true}, function(data) {
    console.log(util.inspect(data));
});

//フォローしている人
twit.get('/friends/list.json', {include_entities:true}, function(data) {
    console.log(util.inspect(data));
 });

//キーワード検索
twit.get('/search/tweets.json', {"q":"#Node"}, function(data) {
    console.log(util.inspect(data));
});