日記

検索エンジニアになりたい

言語処理100本ノック 2015 1日目

言語処理100本ノック(言語処理100本ノック 2015)を見つけたのでやる。使用した言語はPython2.7
途中上手くはてな記法が働いていないところがある

第1章: 準備運動

00. 文字列の逆順
文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

プログラム

#coding: UTF-8
s = "stressed"
print s[::-1]

実行結果
haruka@ubuntu:~/NLP100$ python 00.py
desserts

01. 「パタトクカシーー」
「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

プログラム

#coding: UTF-8

s = u"パタトクカシーー"
print  s[0:1] + s[2:3] + s[4:5] + s[6:7]

実行結果
haruka@ubuntu:~/NLP100$ python 01.py
パトカー
 

02. 「パトカー」+「タクシー」=「パタトクカシーー」
「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

プログラム

#coding: UTF-8

p = u'パトカー'
t = u'タクシー'

for i,j in (zip(p,t)):
  print "".join(i + j)

||< 

実行結果
haruka@ubuntu:~/NLP100$ python 02.py
パタ
トク
カシ
ーー


03. 円周率
"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

プログラム
>|python|
#coding: UTF-8
s = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."

s = s.replace(',',"")
s = s.replace('.',"")
list =[]

for i in s.split():
   list.append(len(i))

print list

 
実行結果
haruka@ubuntu:~/NLP100$ python 03.py
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]


05. n-gram
与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,"I am an NLPer"という文から単語bi-gram,文字bi-gramを得よ.

プログラム
#coding: UTF-8

text = "I am an NLPer"

def ngram(text,n):
  list = []
  if len(text) >= n:
      for i in xrange(len(text) - n + 1):
          list.append(text[i:i+n])
  return list

print ngram(text,2)

 
実行結果
haruka@ubuntu:~/NLP100$ python 05.py
['I ', ' a', 'am', 'm ', ' a', 'an', 'n ', ' N', 'NL', 'LP', 'Pe', 'er']


06. 集合
"paraparaparadise"と"paragraph"に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,'se'というbi-gramがXおよびYに含まれるかどうかを調べよ.

プログラム

#coding: UTF-8
tx1 = "paraparaparadise"
tx2 = "paragraph"

def ngram(text,n):
  list = []
  if len(text) >= n:
      for i in xrange(len(text) - n + 1):
          list.append(text[i:i+n])
  return list

X = (ngram(tx1,2))
Y = (ngram(tx2,2))
print X,Y
print "union:" + X.union(Y)
print "intersection:" + X.intersection(Y)
print "difference:" + X.difference(Y)
||< 

実行結果
haruka@ubuntu:~/NLP100$ python 06.py
['pa', 'ar', 'ra', 'ap', 'pa', 'ar', 'ra', 'ap', 'pa', 'ar', 'ra', 'ad', 'di', 'is', 'se'] ['pa', 'ar', 'ra', 'ag', 'gr', 'ra', 'ap', 'ph']
Traceback (most recent call last):
  File "06.py", line 14, in <module>
    print "union:" + X.union(Y)


07. テンプレートによる文生成
引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y="気温", z=22.4として,実行結果を確認せよ.

プログラム
>|python|
#coding: UTF-8

def template(x,y,z):
  print "%s時の%sは%s" % (x,y,z)

template(12,"気温",22.4)
||< 

実行結果
haruka@ubuntu:~/NLP100$ python 07.py
12時の気温は22.4


08. 暗号文
与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.

英小文字ならば(219 - 文字コード)の文字に置換
その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.

プログラム
>|python|
#coding: UTF-8
text = "This is a pen"

def cipher(text):
  ans = ""
  for i in text:
    if i.islower():
      str = 219 - ord(i)
      ans += chr(str)
    else:
      ans += i
  return ans

print cipher(text)

実行結果
haruka@ubuntu:~/NLP100$ python 08.py
Tsrh rh z kvm

第2章: UNIXコマンドの基礎

hightemp.txtは,日本の最高気温の記録を「都道府県」「地点」「℃」「日」のタブ区切り形式で格納したファイルである.以下の処理を行うプログラムを作成し,hightemp.txtを入力ファイルとして実行せよ.さらに,同様の処理をUNIXコマンドでも実行し,プログラムの実行結果を確認せよ.

10. 行数のカウント
行数をカウントせよ.確認にはwcコマンドを用いよ.

プログラム

#coding: UTF-8

f = open("hightemp.txt")
lines = f.readlines()
print len(lines)
f.close


実行結果
haruka@ubuntu:~/NLP100$ python 10.py
24

コマンド確認
haruka@ubuntu:~/NLP100$ wc -l hightemp.txt
24 hightemp.txt


今日のまとめ
とりあえず100問ざっとみた。さっぱりいまは解ける気がしないけどなんとかなる気がする。
ここに載せてるものでも実行結果がおかしかったりエラーが出ているものがあるのでまずはそれを直す。
今日解けたのは00,01,03,07,08,10

1問解けたら絵をかいたふせんをはってく 
今日のふせんしんちょく
f:id:sakura818uuu:20160510233242j:plain
 

Google A/B test

Googleが最近A/Bテストを行っている。theguardianのこの記事(
Google tests black links in searches | Technology | The Guardian
)が詳しい。

A/Bテストの内容は、検索結果ページのタイトルの部分の色を青にするか黒にするかである。
f:id:sakura818uuu:20160508021608p:plain

いままでは青色を使用していたが、そもそもなぜ青色なのかというと(これはbingだが)こういう話(
「Bing」の検索リンクが青い理由--マイクロソフトが配色決定の裏側を説明 - CNET Japan
)があるらしい。また、この記事(最適なテキストリンクの色は? | ウェブ力学)では色々な検索エンジンのリンクの色について説明している。検索エンジンのリンクの色はほぼ青というのが定石らしい。検索エンジンの色について気にしたことがなかったのでこれからもっと気にかけてみる。

f:id:sakura818uuu:20160510104318p:plain
Googleの検索結果ページをみていると使用している色は背景の白,タイトルの青,URLの緑,キャッシュの濃い緑,見出しや背景の一部となっている灰色,Googleのロゴが元になっているページ選択の赤青緑黄,文字の黒である。色の種類は白灰色黒赤青緑黄の7色だとよくよく見てみると色の濃さや明るさが細かく違っている。それに加えてGoogleはYahooやbingよりも画像をアイコンを表示する数が少ないため色の分散が少ない。こういう話題は論文をみたほうが理解がはやそう。
f:id:sakura818uuu:20160510105356p:plain
f:id:sakura818uuu:20160510105409p:plain


寄り道をしているときにBeyond Ten Blue Links: Enabling User Click Modeling in
Federated Web Search(http://research.microsoft.com/pubs/160720/WSDM12-236-chen.pdf)を見つけた。おもしろい。

追記
検索サービスのビジュアルを刷新しました。 - Yahoo!検索 スタッフブログによると
Yahooでは検索のビジュアルに1年をかけることもあるらしい。

typo

typoには色々な種類がある。
Yahoo!検索スタッフブログのこの記事(あなたの知らないタイピングミスの世界 - Yahoo!検索 スタッフブログ)がとても詳しい。
記事ではタイピングミスパターンを16種類+αに分けている。

  1. すかし…キーを打てたつもりが打ててなかったやつ ex.youtbe
  2. 巻き込み…隣タイプと一緒 ex.tyoutube
  3. ダブル巻き込み…隣タイプと一緒 ex.tygoutube
  4. エンター巻き込み…検索打つ際にエンターをうつときに]も間違って押してしまうこと ex.youtube]
  5. かな打ちミス…かな打ち派の半角/全角忘れ ex.8\a$\2a
  6. 混乱…英語とローマ字が混じったりするやつ ex.Youtubu
  7. 先走り…文字順序を間違えて押してしまうこと ex.youteub
  8. ダブルタップ…1回押すところを2回押してしまうこと ex.youttube
  9. 修正ミス…タイピング途中で打ちやめること ex.youty
  10. 隣タイプ…本来押したいキーに隣接するキーを押してしまうミス ex.toutube
  11. ナンバーロック…Numlockにひっかかっているとき ex.y64t4be
  12. 半角/全角忘れ…半角/全角忘れてるとき ex.ようつべ
  13. 変換事故…間違った漢字などに変換してしまう ex.用tube
  14. 変換忘れ…カタカナや漢字の変換忘れ ex.ゆーちゅーぶ
  15. ポジションずれ…隣タイプと同じ ex.ypitube
  16. かなロック…ひらがな状態でうってしまうミス ex.んらなかなこい
  17. 勘違い…1つの単語を複数に区切ってしまう区切りトラップ及び音引きミス ex.you tube

この16種類+αをもとにtypoを再度自分なりに分類してみると14種類となった。

  1. すかし…キーを打てたつもりが打ててなかったやつ ex.youtbe
  2. 隣タイプ…本来押したいキーに隣接するキーを押してしまうミス ex.toutube
  3. 先走り…文字順序を間違えて押してしまうこと ex.youteub
  4. 勘違い…1つの単語を複数に区切ってしまう区切りトラップ及び音引きミス ex.you tube
  5. エンター巻き込み…検索打つ際にエンターをうつときに]も間違って押してしまうこと ex.youtube]
  6. 無駄 …全然関係ない文字を誤って押してしまうこと ex.youtubez
  7. 混乱…英語とローマ字が混じったりするやつ ex.Youtubu
  8. ダブルタップ…1回押すところを2回押してしまうこと ex.youttube
  9. 修正ミス…タイピング途中で打ちやめること ex.youty
  10. 半角/全角忘れ…半角/全角忘れてるとき ex.ようつべ
  11. 変換事故…間違った漢字などに変換してしまう ex.用tube
  12. 変換忘れ…カタカナや漢字の変換忘れ ex.ゆーちゅーぶ
  13. かなロック…ひらがな状態でうってしまうミス ex.んらなかなこい
  14. ナンバーロック…Numlockにひっかかっているとき ex.y64t4be

実際は様々なユーザーの膨大なtypoのログをみてもしかして機能などを実装するんだろうけどログをもってないのでそこから作ってみた。
下のシュークリームは手打ちで250回シュークリームと入力したもの。

シュークリーム
シュークリーム
シュークリーム
主^クリーム
シュークリーム
主^クリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリ^〜無
シュークリーム
主0クリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
しゅーくりーむs
シュークリ0無
すy0くりーう
シューrクリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
ゆ^くりむ
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークエイーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
すうーくりーむ
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリームs
シュークリーム
シュークリーム
シュークリーム
シュークリーム
主0クリーム
しゅ0くりーむ
シュークリーム
しゅ0くりーむ
しゅ0くりーむ
シュークリーム
シュークリーム
シュークリーム
しゅーくりむ
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
しゅーくりむー
シュークリーム
シュークリーム
シュークリーム
シュークリームs
シュークリーム
シュークリーム
主0クリーム
シュークリーム
シュークリーム
しゅーくりーむs
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
主0クリーム
シュークリーム
シュークリーム
シュークリーム
しゅ0くりーむ
しゅいくりーむ
シュークリーム
シュークリーう
シュー無クリーム
シュークリーム
シュークリーム
シュークリーム
シュークリ〜っ無
しゅ0くりーむ
シュークリーム
シュークリーm
しゅ0くりーm
シュークリーム
シュークリーム
しゅ0くりーむ
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
しゅ0くりーむ
yいーくりむ
シュークリーム
主0クリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーう
シュークリーム
しゅーくり0む
しゅーむりく
しゅーくりーむ
シュークリーム
すうくりーむ
すいいくりーむ
週クリーう
週クリーム
しゅうクリーム
シュウクリーム
しゅうクローム
しゅうくりーむ
シュークリーム
syu-kuri-mu
シュークリーム
シュークリーム
シュークリーム
シュークリーム
しゅーくりーむ
主クリーム
シュークリム
シュークリーム
シュークリーム
シューkリーム
シュークリーム
シュークイーム
シュークリーム
シュークリーム
シュークリーム
しゅ0くりーう
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
しゅ0くり0む
主00クリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
主0クリーム
しゅ0くり0む
主0クリーム
シュークリーク
スークリーム
シュークリーム
シュークエイーム
シュークエイーム
しゅーくえいーう
シュークリーム
シュークリーム
シュークリーム
しゅーkるいむ
シュークリーム
シュークリーム
シュークリーム
主0クリーム
シュークリーm
シュークリーム
シュークリーム
syu-kuri-mu
syu-kurimu
syu-kuri-mu
syu-kuri-mu
syu-kuri0mu
syu-kuri-mu
syu-kuri-mus
syu-kuri-mu
syu-kuri-mu
syu-murimu
syu0kuri-mu
su-kuri-mu
syu-kuri-mu
主0クリーム
シュークリーム
水〜クリーム
シュークリーム
シュークいリーム
シュークリーム
シュークリーム
シュークイーム
シュークリーう
しゅーくりm^む
シュークリーム
シュークリーム
シュークリ^無
シュークリーム
主^〜クリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
シュークリーム
スークリーム
シュークリーム
シュークリーム
シュークリーム
シュークr−無
シュークリーム
主0クリーム
シュークリーム
ゆ¥くr−む
シュークリーム
シュークリーム
シュークリーム
シュークリm
主0クリム
シュークリーム

正しく入力できたシュークリームは158こ,typoしたシュークリームは92こである。
全てのシュークリームは250こなので正しいシュークリームは63.2%,typoしたシュークリームは36.8%である。
55種類のtypoがあり、出現頻度は以下の通り。

主0クリーム:10
syu-kuri-mu:9
しゅ0くりーむ:7
シュークエイーム:3
シュークリーう:3
シュークリームs:2
シュークイーム:2
シュークリーm:2
シュークリム:2
スークリーム:2
しゅーくりーむs:2
しゅ0くり0む:2
主^クリーム:2
シュークリm:1
シューkリーム:1
シューrクリーム:1
シュークいリーム:1
シュークリ0無:1
シュークリ^無:1
シュークリ^〜無:1
シュー無クリーム:1
シュークリ〜っ無:1
シュークr−無:1
ゆ^くりむ:1
ゆ¥くr−む:1
yいーくりむ:1
すうくりーむ:1
すうーくりーむ:1
すいいくりーむ:1
すy0くりーう:1
しゅーくりむ:1
しゅーむりく:1
しゅーくりむー:1
しゅーkるいむ:1
しゅうクリーム:1
しゅうクローム:1
しゅいくりーむ:1
しゅうくりーむ:1
しゅ0くりーう:1
しゅ0くりーm:1
しゅーくりm^む:1
しゅーくえいーう:1
主0クリム:1
主00クリーム:1
主^〜クリーム:1
週クリーう:1
週クリーム:1
主クリーム:1
水〜クリーム:1
syu-kurimu:1
syu-kuri0mu:1
syu-kuri-mus:1
syu-murimu:1
syu0kuri-mu:1
su-kuri-mu:1

次はそれぞれのtypoを14種類に分類し集計する。

主0クリーム:10→隣タイプ+変換事故
syu-kuri-mu:9→半角/全角忘れ
しゅ0くりーむ:7→隣タイプ+変換忘れ
シュークエイーム:3→隣タイプ
シュークリーう:3→すかし+変換事故
シュークリームs:2→無駄
シュークイーム:2→すかし
シュークリーm:2→すかし
シュークリム:2→すかし
スークリーム:2→すかし
しゅーくりーむs:2→変換忘れ+無駄
しゅ0くり0む:2→隣タイプ+変換忘れ
主^クリーム:2→隣タイプ+変換事故
シュークリm:1→すかし
シューkリーム:1→すかし
シューrクリーム:1→無駄
シュークいリーム:1→無駄
シュークリ0無:1→変換事故+隣タイプ
シュークリ^無:1→変換事故+隣タイプ
シュークリ^〜無:1→変換事故+隣タイプ
シュー無クリーム:1→無駄
シュークリ〜っ無:1→変換事故+隣タイプ+無駄
シュークr−無:1→変換事故+すかし
ゆ^くりむ:1→変換忘れ+すかし+隣タイプ
ゆ¥くr−む:1→変換忘れ+すかし+無駄
yいーくりむ:1→変換忘れ+すかし+隣タイプ
すうくりーむ:1→変換忘れ+すかし+隣タイプ
すうーくりーむ:1→変換忘れ+すかし+隣タイプ
すいいくりーむ:1→変換忘れ+すかし+隣タイプ
すy0くりーう:1→変換忘れ+すかし+隣タイプ
しゅーくりむ:1→変換忘れ+すかし
しゅーむりく:1→変換忘れ+先走り+すかし
しゅーくりむー:1→変換忘れ+先走り
しゅーkるいむ:1→変換忘れ+隣タイプ+すかし
しゅうクリーム:1→変換忘れ
しゅうクローム:1→変換忘れ+隣タイプ
しゅいくりーむ:1→変換忘れ+隣タイプ
しゅうくりーむ:1→変換忘れ
しゅ0くりーう:1→変換忘れ+すかし+隣タイプ
しゅ0くりーm:1→変換忘れ+すかし+隣タイプ
しゅーくりm^む:1→変換忘れ+すかし+隣タイプ
しゅーくえいーう:1→変換忘れ+隣タイプ
主0クリム:1→変換事故+隣タイプ+すかし
主00クリーム:1→変換事故+隣タイプ+ダブルタップ
主^〜クリーム:1→変換事故+隣タイプ+ダブルタップ
週クリーう:1→変換事故+すかし
週クリーム:1→変換事故
主クリーム:1→変換事故+すかし
水〜クリーム:1→変換事故+隣タイプ+すかし
syu-kurimu:1→半角/全角忘れ+すかし
syu-kuri0mu:1→半角/全角忘れ+隣タイプ
syu-kuri-mus:1→半角/全角忘れ+無駄
syu-murimu:1→半角/全角忘れ+すかし+隣タイプ
syu0kuri-mu:1→半角/全角忘れ+隣タイプ
su-kuri-mu:1→半角/全角忘れ+すかし

以下がtypoの種類分けした後の集計結果。左の番号は上記で14種類に分類分けしたときの番号。

  1. すかし…34
  2. 隣タイプ…48
  3. 先走り…2
  4. 勘違い…0
  5. エンター巻き込み…0
  6. 無駄 …10
  7. 混乱…0
  8. ダブルタップ…2
  9. 修正ミス…0
  10. 半角/全角忘れ…15
  11. 変換事故…27
  12. 変換忘れ…30
  13. かなロック…0
  14. ナンバーロック…0

いままでの結果を集計するとこのようになった。
隣タイプ、すかし、変換忘れ、変換事故が上位を占めた。想定していたよりも隣タイプが多かったことに驚いた(これはただ単に自分のタイピングの癖なのかもしれない)。また、今回は入力するキーワードがシュークリームってわかってる前提だからゆ¥くr−むがシュークリームと認識できるけど、前提がない場合だと目的のキーワードと認識するのに難しいかもしれない。

シュークリーム 250こ-正しいシュークリーム 158こ(63.2%)
                    |
                    |-typoしたシュークリーム 92こ(36.8%)
                        |
                        |-隣タイプ 48こ(19.2%)
                        |-すかし 34こ(13.6%)
                        |-変換忘れ 30こ(12%)
                        |-変換事故 27こ(10.8%)
                        |-半角/全角忘れ 15こ(6%)
                        |-無駄 10こ(4%)
                        |-先走り 2こ(0.8%)
                        |-ダブルタップ 2こ(0.8%)

タブ多すぎ問題

普通にインターネットを使用しているとこんなことになる。
f:id:sakura818uuu:20160509172420p:plain


6こだとほどよい
f:id:sakura818uuu:20160509172527p:plain

12こだとまあまだ常識の範疇
f:id:sakura818uuu:20160509172630p:plain

18こだと多少苦しいがアイコンとタイトルの1文字目が見えるのでまだなんとかなる
f:id:sakura818uuu:20160509172800p:plain

24こはクリックしたいタブにマウスをもってくのがたるくなる
f:id:sakura818uuu:20160509172926p:plain

30こはもはやタイトルが見えない
f:id:sakura818uuu:20160509173035p:plain

36こはクリックしたいのにページを消すばってんボタンがおささる
f:id:sakura818uuu:20160509173203p:plain

42こはアイコンが消える 
f:id:sakura818uuu:20160509173314p:plain

48こはもういい
f:id:sakura818uuu:20160509173442p:plain

このようにタブがふえるについて困ることは多々ある。
そこでクローム拡張機能を導入してみた。

1.TooManyTabs for Chrome(Chrome用TooManyTabs - Chrome ウェブストア)
タブを整理したりソートできるやつ。使い心地はいまのところいまいち。
f:id:sakura818uuu:20160509180341p:plain
f:id:sakura818uuu:20160509180502p:plain

2.Tabman Tabs Manager(Tabman Tabs Manager - Chrome ウェブストア)
タブを縦一列にシンプルに表示する。いいかもしれない。
f:id:sakura818uuu:20160509180440p:plain
f:id:sakura818uuu:20160509180450p:plain

3.Show Title Tag(Show Title Tag - Chrome Web Store)
タグがふえすぎてしまったときにそのページに矢印を少し静止させないとページのタイトルが表示されない。Show Title Tagはそれを解消するもので画面の右下に小さくページタイトルを表示する。実際使ってみるとタブの目線は画面の一番上なのにこの機能が表示されるのは画面の一番下なので視線を動かすのがめんどい。
f:id:sakura818uuu:20160509180809p:plain
f:id:sakura818uuu:20160509180817p:plain

4.Tab Resize split screen layouts(Tab Resize - split screen layouts - Chrome Web Store)
これはタブ自体をどうにかするというよりタブを分割したりするのに使う。私のパソコンのモニター画面が小さいので活躍する場面はなさそう。
f:id:sakura818uuu:20160509180838p:plain
f:id:sakura818uuu:20160509181134p:plain

5.One Tab(OneTab - Chrome Web Store)
全てのタブを1つのタブにまとめる拡張機能。結構長い間使い続けたが合わなかった。
f:id:sakura818uuu:20160509181400p:plain


結果としてTabman Tabs Managerはいいかんじ。タブのメモリ問題を解決するのもいいんだけど、やっぱり見た目(使いやすさ)のタブ多すぎ問題はどうすればいいんだろう。タブが12こを超えると自動的にウィンドウが新しく立ち上がるとか?そうなるとウィンドウ間の移動がめんどくさいし‥タブを2段に表示するとか‥?うーん

いろんな検索エンジン

検索エンジンといったらGoogleやYahooが有名だがそれ以外にもたくさんある。

Google
説明が必要がない。検索エンジン界の王様。
f:id:sakura818uuu:20160509150419p:plain
f:id:sakura818uuu:20160509150425p:plain

Yahoo
2009年にMicrosoftと提携し(ニュース - Yahoo!とMicrosoftが検索事業で10年にわたる提携を正式発表:ITpro)、さらには2010年にGoogleと提携した。日本での普及率が高い。
f:id:sakura818uuu:20160509150437p:plain
f:id:sakura818uuu:20160509150447p:plain

Bing
Microsoft社の検索エンジン。日本だと普及率は低いが米国では普及率はそこそこ。
f:id:sakura818uuu:20160509150500p:plain
f:id:sakura818uuu:20160509150515p:plain

Carrot2
左側にカテゴリ分けがされている。Image検索が使用できないのはなんなのか
f:id:sakura818uuu:20160509143914p:plain
f:id:sakura818uuu:20160509143923p:plain

million short
検索結果のtop100件を削除しちゃうよという斬新なシステムを搭載している。一体なんのメリットがあるのか
f:id:sakura818uuu:20160509143943p:plain
f:id:sakura818uuu:20160509143952p:plain

Yandex
ロシアでGoogleよりも普及率が高いとされている検索エンジン。ロシアだと使い勝手はいい
f:id:sakura818uuu:20160509144008p:plain
f:id:sakura818uuu:20160509144015p:plain

Baidu
中国最大の検索エンジン。セキュリティ関連でたまにやらかす
f:id:sakura818uuu:20160509144029p:plain
f:id:sakura818uuu:20160509144039p:plain

DuckDuckGo
通称あひる。プライバシーに力をいれていてユーザーを追跡しない検索というのが売り
f:id:sakura818uuu:20160509144128p:plain
f:id:sakura818uuu:20160509144139p:plain

Qwant
デザインがちょっとおしゃれな検索エンジン。何が特徴だったのか思い出せないくらいには印象が薄い。プライバシー関連に力を入れていた気がする。
f:id:sakura818uuu:20160509144157p:plain
f:id:sakura818uuu:20160509144208p:plain

Qwory
ついさっきTwitterで知らない外国人が教えてくれた検索エンジン。"花より男子"の検索結果は0件なのでかなしい
f:id:sakura818uuu:20160509155129p:plain
f:id:sakura818uuu:20160509155138p:plain



Googleが一番好きだが個人的にはDuckDuckGoを応援している。

検索技術の動向を知るのにいいかんじの3つのサイト

検索技術の動向を知るのにいいかんじの3つのサイトを紹介する。

1つめ
Google Research Blog(http://googleresearch.blogspot.jp/)
Google公式のGoogleの検索技術を中心に取り扱ったサイト。
f:id:sakura818uuu:20160509131539p:plain

2つめ
Yahoo!検索スタッフブログ(http://searchblog.yahoo.co.jp/)
Yahoo公式のYahooの検索技術を中心に取り扱ったサイト。日本語。
f:id:sakura818uuu:20160509131550p:plain

3つめ
Search Engine Land(http://searchengineland.com/)
検索業界のニュースを知るといったらこれという超有名サイト。
f:id:sakura818uuu:20160509131601p:plain


ちなみに日本国内での検索エンジンのシェアは1位Google,2位Yahoo,3位Bingである。(1位Yahoo,2位Google,3位Bingといってるところもある。)
statcounter(StatCounter Global Stats - Browser, OS, Search Engine including Mobile Usage Share)での集計結果だと、2016年4月時点でGoogle(61.23%),Yahoo(31.09%),Bing(7.05%)である(下記の画像を参照)。statcounterの集計方法を詳しく知らないためなんともいえないがとりあえず日本ではGoogleとYahooの2強である。(検索エンジンのシェアを見るためにはどこを一番信用したらいいんだろう…。)
f:id:sakura818uuu:20160509131929p:plain

クローラのコードを読む

クローラをつくるにあたってサンプルコード(https://github.com/REMitchell/python-scraping/blob/master/chapter3/3-crawlSite.py)を読んでみる。

サンプルコードの出典は最後に明記してある。
以下がサンプルコードの全体。

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import datetime
import random

pages = set()
random.seed(datetime.datetime.now())

#Retrieves a list of all Internal links found on a page
def getInternalLinks(bsObj, includeUrl):
    internalLinks = []
    #Finds all links that begin with a "/"
    for link in bsObj.findAll("a", href=re.compile("^(/|.*"+includeUrl+")")):
        if link.attrs['href'] is not None:
            if link.attrs['href'] not in internalLinks:
                internalLinks.append(link.attrs['href'])
    return internalLinks
            
#Retrieves a list of all external links found on a page
def getExternalLinks(bsObj, excludeUrl):
    externalLinks = []
    #Finds all links that start with "http" or "www" that do
    #not contain the current URL
    for link in bsObj.findAll("a", href=re.compile("^(http|www)((?!"+excludeUrl+").)*$")):
        if link.attrs['href'] is not None:
            if link.attrs['href'] not in externalLinks:
                externalLinks.append(link.attrs['href'])
    return externalLinks

def splitAddress(address):
    addressParts = address.replace("http://", "").split("/")
    return addressParts

def getRandomExternalLink(startingPage):
    html = urlopen(startingPage)
    bsObj = BeautifulSoup(html)
    externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0])
    if len(externalLinks) == 0:
        internalLinks = getInternalLinks(startingPage)
        return getNextExternalLink(internalLinks[random.randint(0, 
                                  len(internalLinks)-1)])
    else:
        return externalLinks[random.randint(0, len(externalLinks)-1)]
    
def followExternalOnly(startingSite):
    externalLink = getRandomExternalLink("http://oreilly.com")
    print("Random external link is: "+externalLink)
    followExternalOnly(externalLink)
            
followExternalOnly("http://oreilly.com")

以上のコードを少しずつ区切って読んでいく。まず一番下の行のfollowExternalOnly("http://oreilly.com")はオライリーの公式サイトのURLにfollowExternalOnly関数を適用する。

def followExternalOnly(startingSite):
    externalLink = getRandomExternalLink("http://oreilly.com")
    print("Random external link is: "+externalLink)
    followExternalOnly(externalLink)

followExternalOnly(startingSite):よりオライリーの公式サイトがなにかのはじめとなるURLだということがわかる。externalLink = getRandomExternalLink("http://oreilly.com")でオライリーの公式サイトから関連するリンクをランダムで取得しそれをprintする関数だと推測する。followExternalOnly(externalLink)でこの関数自体を再帰している…と思う。

def getRandomExternalLink(startingPage):
    html = urlopen(startingPage)
    bsObj = BeautifulSoup(html)
    externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0])
    if len(externalLinks) == 0:
        internalLinks = getInternalLinks(startingPage)
        return getNextExternalLink(internalLinks[random.randint(0, 
                                  len(internalLinks)-1)])
    else:
        return externalLinks[random.randint(0, len(externalLinks)-1)]

getRandomExternalLink(startingPage):よりオライリーの公式サイトがなにかのはじめとなるページだということがわかる。
html = urlopen(startingPage)
bsObj = BeautifulSoup(html)
でページ全体を取り出してBeautifulSoupオブジェクトを作っている。
externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0])はbsObjとsplitAddress関数の0番目をgetExternalLinks関数でなんらかの処理をしている。

if len(externalLinks) == 0:
        internalLinks = getInternalLinks(startingPage)
        return getNextExternalLink(internalLinks[random.randint(0, 
                                  len(internalLinks)-1)])
    else:
        return externalLinks[random.randint(0, len(externalLinks)-1)]

ここはもしexternalLinksの長さが0だった場合、getInternalLinks関数でそのスタートページ内のリンクのリストを取り出して…ランダムでその中から1つ選択する…?

def splitAddress(address):
    addressParts = address.replace("http://", "").split("/")
    return addressParts

splitAddress関数はaddressを/で分割する関数。address.replace("http://", "")でhttp://を空文字列に置き換えてるようだけどなぜ置き換えてるの…?

def getExternalLinks(bsObj, excludeUrl):
    externalLinks = []
    #Finds all links that start with "http" or "www" that do
    #not contain the current URL
    for link in bsObj.findAll("a", href=re.compile("^(http|www)((?!"+excludeUrl+").)*$")):
        if link.attrs['href'] is not None:
            if link.attrs['href'] not in externalLinks:
                externalLinks.append(link.attrs['href'])
    return externalLinks

getExternalLinks関数はページ内でみつかったhttpまたはwwwではじまるURLを探し出す関数。

def getInternalLinks(bsObj, includeUrl):
    internalLinks = []
    #Finds all links that begin with a "/"
    for link in bsObj.findAll("a", href=re.compile("^(/|.*"+includeUrl+")")):
        if link.attrs['href'] is not None:
            if link.attrs['href'] not in internalLinks:
                internalLinks.append(link.attrs['href'])
    return internalLinks

getInternalLinks関数はページ内でみつかった/ではじまるURLを探し出す関数。

冗長な説明になってしまったがコードの意味はわかるようになった。


サンプルコードの出典
『Web Scraping with Python』 Ryan Mitchell、 O'Reilly、 Copyright 2015 Ryan Mitchell、 978-1-491-91029-0、 邦題『PythonによるWebスクレイピングオライリー・ジャパン、 ISBN978-4-87311-761-4

より3.3 crawlSite.py(https://github.com/REMitchell/python-scraping/blob/master/chapter3/3-crawlSite.py)

groongaのチュートリアル4.1

groongaのチュートリアル4.1(
4.1. 基本的な操作 — Groonga v6.0.2ドキュメント
)を行った。基本的にはSQLのような操作。offset関数は指定した次の値から表示されるのに注意。

わからなかったこと
4.1.1.5検索結果の並び替えでのselect --table Site --query title:@test --output_columns _id,_score,title --sortby -_scoreおよびselect --table Site --query title:@test --output_columns _id,_score,title --sortby -_score,_idの実行結果がWebページに記載されている結果と異なってしまう。
実行結果が整形されていない(なにか方法があった気がするので後で調べる)。
対話モードだと↑←が効かない。履歴を見たり打ち間違えた時に戻れなかったりするので不便。

haruka@ubuntu:~$ cd db
haruka@ubuntu:~/db$ groonga -n introduction.db
> status
[[0,1462724112.03547,0.0190560817718506],{"alloc_count":238,"starttime":1462724107,"start_time":1462724107,"uptime":5,"version":"6.0.1","n_queries":0,"cache_hit_rate":0.0,"command_version":1,"default_command_version":1,"max_command_version":2}]
> table list
-22,1462724516.96678,0.000232696533203125,"invalid command name: table",[["grn_ctx_qe_exec","ctx.c",1625]]
> column list
-22,1462724540.70943,0.000256776809692383,"invalid command name: column",[["grn_ctx_qe_exec","ctx.c",1625]]
> table_create --name Site --flags TABLE_HASH_KEY --key_type ShortText
[[0,1462724789.13796,0.0459518432617188],true]
> select --table Site
[[0,1462724846.46995,0.000674247741699219],[[[0],[["_id","UInt32"],["_key","ShortText"]]]]]
> column_create --table Site --name title --type ShortText
[[0,1462726805.2041,0.0678045749664307],true]
> select --table Site
[[0,1462726835.8324,0.000177860260009766],[[[0],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]]]]]
> load --table Site
> load --table Site
[
{"_key":"http://example.org/","title":"This is test record 1!"},
{"_key":"http://example.net/","title":"test record 2."},
{"_key":"http://example.com/","title":"test test record three."},
{"_key":"http://example.net/afr","title":"test record four."},
{"_key":"http://example.org/aba","title":"test test test record five."},
{"_key":"http://example.com/rab","title":"test test test test record six."},
{"_key":"http://example.net/atv","title":"test test test record seven."},
{"_key":"http://example.org/gat","title":"test test record eight."},
{"_key":"http://example.com/vdw","title":"test test record nine."},
][[-22,1462726888.33685,41.9003500938416,"JSON must start with '[' or '{': ","json_read","db.c",13278],0]
> -22,1462726930.23731,0.000177145004272461,"invalid command name: [",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.23754,0.000164985656738281,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.23774,1.43051147460938e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.23779,1.16825103759766e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.23783,1.09672546386719e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.23786,1.12056732177734e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.2379,1.07288360595703e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.23793,1.04904174804688e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.23797,1.07288360595703e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
> -22,1462726930.238,1.07288360595703e-05,"invalid command name: {",[["grn_ctx_qe_exec","ctx.c",1625]]
>
[[-22,1462726935.97161,0.000230550765991211,"invalid command name: ]","grn_ctx_qe_exec","ctx.c",1625]]
> load --table Site
[
{"_key":"http://example.org/","title":"This is test record 1!"},
{"_key":"http://example.net/","title":"test record 2."},
{"_key":"http://example.com/","title":"test test record three."},
{"_key":"http://example.net/afr","title":"test record four."},
{"_key":"http://example.org/aba","title":"test test test record five."},
{"_key":"http://example.com/rab","title":"test test test test record six."},
{"_key":"http://example.net/atv","title":"test test test record seven."},
{"_key":"http://example.org/gat","title":"test test record eight."},
{"_key":"http://example.com/vdw","title":"test test record nine."},
]> > > > > > > > > > >
[[0,1462726961.04945,5.56129145622253],9]
> select --table Site
[[0,1462727019.55979,0.000241994857788086],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[1,"http://example.org/","This is test record 1!"],[2,"http://example.net/","test record 2."],[3,"http://example.com/","test test record three."],[4,"http://example.net/afr","test record four."],[5,"http://example.org/aba","test test test record five."],[6,"http://example.com/rab","test test test test record six."],[7,"http://example.net/atv","test test test record seven."],[8,"http://example.org/gat","test test record eight."],[9,"http://example.com/vdw","test test record nine."]]]]
> select --table Site --query _id:1
[[0,1462727071.14666,0.0910372734069824],[[[1],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[1,"http://example.org/","This is test record 1!"]]]]
> select --table Site --query '_key:"http://example.org/"'
[[0,1462727156.25137,0.00113058090209961],[[[1],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[1,"http://example.org/","This is test record 1!"]]]]
> table_create --name Terms --flags TABLE_PAT_KEY --key_type ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
[[0,1462727328.51775,0.0586590766906738],true]
> select --table Site --offset 0 --limit3
[[0,1462758572.72974,0.00013279914855957],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[1,"http://example.org/","This is test record 1!"],[2,"http://example.net/","test record 2."],[3,"http://example.com/","test test record three."],[4,"http://example.net/afr","test record four."],[5,"http://example.org/aba","test test test record five."],[6,"http://example.com/rab","test test test test record six."],[7,"http://example.net/atv","test test test record seven."],[8,"http://example.org/gat","test test record eight."],[9,"http://example.com/vdw","test test record nine."]]]]
> select --table Site -- offset 0 -- limit 3
-22,1462758640.96341,0.000414133071899414,"invalid table name: <-->",[["grn_select","proc_select.c",877]]
> select --table Site --offset 0 --limit 3
[[0,1462758666.76998,0.000222206115722656],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[1,"http://example.org/","This is test record 1!"],[2,"http://example.net/","test record 2."],[3,"http://example.com/","test test record three."]]]]
> select --table Site --offset 3 --limit 3
[[0,1462758745.12413,0.00038909912109375],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[4,"http://example.net/afr","test record four."],[5,"http://example.org/aba","test test test record five."],[6,"http://example.com/rab","test test test test record six."]]]]
> select --table Site --offset 7 --limit 3
[[0,1462758791.24307,0.000257968902587891],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[8,"http://example.org/gat","test test record eight."],[9,"http://example.com/vdw","test test record nine."]]]]
> select --table Site --sortby -_id
[[0,1462758849.9427,0.000440359115600586],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[9,"http://example.com/vdw","test test record nine."],[8,"http://example.org/gat","test test record eight."],[7,"http://example.net/atv","test test test record seven."],[6,"http://example.com/rab","test test test test record six."],[5,"http://example.org/aba","test test test record five."],[4,"http://example.net/afr","test record four."],[3,"http://example.com/","test test record three."],[2,"http://example.net/","test record 2."],[1,"http://example.org/","This is test record 1!"]]]]
> select --table Site --sortby -_key
[[0,1462758910.3005,0.000372648239135742],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[8,"http://example.org/gat","test test record eight."],[5,"http://example.org/aba","test test test record five."],[1,"http://example.org/","This is test record 1!"],[7,"http://example.net/atv","test test test record seven."],[4,"http://example.net/afr","test record four."],[2,"http://example.net/","test record 2."],[9,"http://example.com/vdw","test test record nine."],[6,"http://example.com/rab","test test test test record six."],[3,"http://example.com/","test test record three."]]]]
> select --table Sit --query title:@test --output_colums _id,_score,title --sortby -_score
[[-22,1462759019.66426,0.000590085983276367,"invalid table name: ","grn_select","proc_select.c",877]]
> select --table Sit --query title:@test --output_colums _id,_score,title --sortby -_score
[[-22,1462759033.99363,8.7738037109375e-05,"invalid table name: ","grn_select","proc_select.c",877]]
> select --table Site --query title:@test --output_colums _id,_score,title --sortby -_score
[[0,1462759091.04822,0.033463716506958],[[[9],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[1,"http://example.org/","This is test record 1!"],[9,"http://example.com/vdw","test test record nine."],[3,"http://example.com/","test test record three."],[5,"http://example.org/aba","test test test record five."],[4,"http://example.net/afr","test record four."],[6,"http://example.com/rab","test test test test record six."],[8,"http://example.org/gat","test test record eight."],[7,"http://example.net/atv","test test test record seven."],[2,"http://example.net/","test record 2."]]]]
> select --table Site --query title:@test --output_columns _id,_score,title --sortby -_score
[[0,1462759198.70156,0.00127553939819336],[[[9],[["_id","UInt32"],["_score","Int32"],["title","ShortText"]],[1,1,"This is test record 1!"],[9,1,"test test record nine."],[3,1,"test test record three."],[5,1,"test test test record five."],[4,1,"test record four."],[6,1,"test test test test record six."],[8,1,"test test record eight."],[7,1,"test test test record seven."],[2,1,"test record 2."]]]]
> select --table Site --query title:@test --output_columns _id,_score,title --sortby -_score,_id
[[0,1462760159.56464,0.00125956535339355],[[[9],[["_id","UInt32"],["_score","Int32"],["title","ShortText"]],[1,1,"This is test record 1!"],[2,1,"test record 2."],[3,1,"test test record three."],[4,1,"test record four."],[5,1,"test test test record five."],[6,1,"test test test test record six."],[7,1,"test test test record seven."],[8,1,"test test record eight."],[9,1,"test test record nine."]]]]
>

はてなブログでPythonのコードを貼り付ける方法

Pythonのコードを貼り付けるためにまず編集方法を見たまま記法からはてな記法に変更する。見たまま記法からはてな記法に変更するときは本文の内容が消去されるので注意。

f:id:sakura818uuu:20160508220246p:plain

タイトル上部にある[編集]の下矢印を押す。
f:id:sakura818uuu:20160508220525p:plain
はてな記法を選択する。

 

Pythonのコードを書きたいところに”>|python|”と”||<”でコードを挟むような記法で書く。最初のPを大文字にした”>|Python|”では上手く行かない。

 

>|python|

ここにPythonのコード

||< 

 

”>|python|”のところをjavaなど他の言語に置き換えることも可能。例えばJavaのときは以下のように書く。

>|java|

ここにJavaのコード

||< 

 

 

スクレイピングしてスニペットを取得する

検索結果を表示するときにそのページのスニペットが必要となる。

f:id:sakura818uuu:20160508025821p:plain


ここではWikipediaのグーグル紹介ページ(Google - Wikipedia)のスニペットに該当する部分をスクレイピングして取得した。言語はPython3,ライブラリはbeautifulsoupを使用した。

from bs4 import BeautifulSoup
from urllib.request import urlopen
import re

html = urlopen("https://ja.wikipedia.org/wiki/google")
bsObj = BeautifulSoup(html.read())
print(bsObj.p)

実行すると以下のようになる。
f:id:sakura818uuu:20160508025959p:plain

タグやURLを除去できていないため修正する必要がある。