子供の落書き帳 Remix

15/4/13:ひと月に一度更新するブログになってしまっている

sedでスペースをタブに置換 (連続スペースは1文字とみなす)
2018/07/08(日) 12:57:29

きっかけ


Linuxのmpstatで取ったパフォーマンスの記録をExcelに貼り付ける必要があった。
Excelでは空白区切りを認識しないので、空白(半角スペース)をタブに変換したい。
このとき、連続する空白は1つのタブ記号に置換したい。
(連続しない1つだけ単独の空白も1つのタブ記号に置換したい。)

Linuxコマンドのsedを使ってやってみた。
(Excelの「テキスト ファイル ウィザード」を使えば可能ではあるが、GUIで大変なので)

環境 (sedのバージョン)


GNU sed、BSD sed、POSIXとかで微妙に挙動が違うらしい……

BSD sed などに代表される POSIX に準拠した sed は OS X などで標準で使用されているが、一般的な Linux で用いられる sed は後述する GNU sed であることが多い。ゆえに、Linux ユーザが OS X の sed を使用するとオプションなどのいわゆる「方言」的な違いに混乱することでしょう。
sed コマンドの用法 - Qiita


この記事では、以下の環境で確認した。

cygwin 64bit版

$ sed --version
sed (GNU sed) 4.2.2
Copyright (C) 2012 Free Software Foundation, Inc.
(後略)



「正規表現を有効にする」には?


正確には「拡張正規表現(extended regular expressions)を有効にする」らしい。
拡張正規表現なしでsedを使っても一部の正規表現は使えるが、普段の正規表現のやり方と微妙に違ったり、使えない演算子があったりして、かえってややこしい。
拡張正規表現を有効にしておいたほうが分かりやすい。

「-r -eを使おう」と書いてあるサイトと、
「-Eを使おう」と書いてあるサイトがある。

-eは「コマンドの指定をする」オプションであるため、
「-r -e コマンド」だと正しく動くが、「-e -r コマンド」だと-eとコマンドが離れているためエラーになる。
しか実のところ、-eは省略しても良いらしい。謎だ……。

置換の指定コマンド



以下のどれか1つ。
's/ +/\t/g'
's/\s+/\t/g'
's/ {1,}/\t/g'
's/\s{1,}/\t/g'


s : 置換
g : 行の全体で置換を実行 (つけないと行内で最初に出てきたスペースだけ置換される)

\s 空白とタブ両方に対応する
+ 1回以上の連続
{n,} で「n回以上の連続」を指定できる。

\sを使った方法は、入力にタブが無ければ期待通りに動く。

まとめ



最終的に、
「入力ファイルのスペースをタブに変換して出力する、ただし連続したスペースは1つのタブに変換する」
コマンドは、以下の通りである。

以下のどれか1つ。(ファイル名をinput.txt, output.txtとする)
sed -E 's/ +/\t/g' input.txt > output.txt
sed -E 's/\s+/\t/g' input.txt > output.txt
sed -E 's/ {1,}/\t/g' input.txt > output.txt
sed -E 's/\s{1,}/\t/g' input.txt > output.txt

「-E」の代わりに「-r -e」でもよい。「-r」でもよい。
  1. 2018/07/08(日) 12:57:29|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0

pythonの正規表現のmatch, search, findall関数の違いを調べて整理した
2018/07/01(日) 22:18:41

以下のサイトが役に立った。自分で調査した結果も併せて整理しておく。
Pythonでの正規表現の使い方 - Qiita
正規表現 HOWTO ? Python 3.6.5 ドキュメント

共通


pythonのバージョンは3.6.0。

正規表現でマッチするものが見つかったときには、matchオブジェクトというオブジェクトが使われる。
matchオブジェクトの中に、マッチした箇所の情報が格納される。
(今回はmatchオブジェクトの中身の構造については触れない)

match関数 文字列の先頭だけを探す


これは検索対象の先頭からだけ検索して、マッチするものがあるか判定する。
探しているパターンが先頭にあればマッチするが、途中に含まれていてもマッチしない。

・マッチしなかったらNoneが返る。
・マッチした場合はmatchオブジェクトが返る。
・matchオブジェクトの中にはマッチした箇所の情報が入っている。

以下は特殊なシンタックスを使わない、ごく単純な例だ。
下の例の2つ目では、では"regular expression"の中に"lar"は含まれているが、最初ではないのでマッチせず、Noneが返っている。


import re

result = re.match("reg", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(0, 3), match='reg'>
#

result = re.match("lar", "regular expression")
print(result)
print(type(result))
# 出力:
# None
#



search関数 文字列の全ての位置を探す。


これは検索対象の位置にかかわらず検索する。


result = re.search("reg", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(0, 3), match='reg'>
#

result = re.search("lar", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(4, 7), match='lar'>
#


文字列の途中でもマッチしているのが、match関数と違う点である。
また、マッチしない場合は、match関数と同様にNoneが返る。

search関数の注意:パターンにマッチするのが2つ以上ある場合は最初の1つだけが返る。

"regular expression"の中で、「アルファベットが1文字以上連続する箇所」を探してみよう。
これは「\w+」と書き表せる。
(厳密には、\wはアルファベット、数字、およびアンダースコアの集合である)
このパターンに該当するのは「regular」と「expression」の2つだが、返り値を見ると最初の「regular」の部分だけが入っている。


result = re.search("\w+", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(0, 7), match='regular'>
#



findall関数 パターンに当てはまるもの全てをリストにして返す



マッチする箇所が複数あったら、1つ目だけではなく全て返してほしい、という場合もあるだろう。
このような場合ではfindall関数を使う。

返り値の決まり方は結構ややこしい。
Python 3.6.5 ドキュメントのre.findallの箇所にはこう書かれている。
「Return all non-overlapping matches of pattern in string, as a list of strings. (中略) If one or more groups are present in the pattern, return a list of groups; this will be a list of tuples if the pattern has more than one group. 」
3つの場合分けがある。順に見ていこう。

まず、1つ目の場合。パターンの指定時にグルーピングの( )を使わない場合、返り値は文字列のリストである。

result = re.findall("\w+", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# ['regular', 'expression']
#
#



グルーピングの( )を使う場合、まずパターン内に( )が1つだけであれば、グループ(内にある文字列)のリストになる。
下の例の2つ目では、マッチングは1つ目の例と同様になるが、( )の中にeが入っていないので返り値にeが含まれていない。

result = re.findall("(e.)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# ['eg', 'ex', 'es']
#
#

result = re.findall("e(.)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# ['g', 'x', 's']
#
#


そしてパターン内に( )が2つ以上ある場合、グループ(内にある文字列)をタプルにしたもののリストになる。
下の例の2つ目では( )がネスト(入れ子)になっているが、タプル内の順序は左括弧の登場順である。

result = re.findall("(e)(.)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# [('e', 'g'), ('e', 'x'), ('e', 's')]
#
#

result = re.findall("(e)((.)..)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# [('e', 'gul', 'g'), ('e', 'xpr', 'x'), ('e', 'ssi', 's')]
#
#



最後に、返り値の方式にかかわらず、マッチしない場合は空のリストが返る。

result = re.findall("AAAAA", "regular expression")
print(result)
print(type(result))
# 出力:
# []
#



まとめ


3つの関数の仕様を整理しておこう。
■match関数は文字列の先頭だけを探す。
■search関数は文字列の全ての位置を探す。パターンに当てはまるものが複数ある場合は最初のものを返す。
■findall関数は文字列の全ての位置を探す。パターンに当てはまるもの全てをリストにして返す。返り値は以下の3通りある:
  -パターンの指定にグルーピングの( )を使わない場合、返り値は文字列のリストである。
  -パターンの指定にグルーピングの( )を使う場合、パターン内に( )が1つだけであれば、グループ(内にある文字列)のリストになる。
  -パターンの指定にグルーピングの( )を使う場合、パターン内に( )が2つ以上であれば、グループ(内にある文字列)をタプルにしたもののリストになる。


書いたきっかけとおまけ



正規表現でsearchを使うべきところでmatchを使っていて、ずっとNoneが返ってきてしまい、だいぶ時間を費やした。

何も考えずに「python 正規表現」でググったとき、python公式ドキュメントで最初に見つかるのはこれだ。
6.2. re ? 正規表現操作 ? Python 3.6.5 ドキュメント
これはリファレンスであり、初めて使う人が参考にするには厳しい。
終わり近くの6.2.5.3. search() vs. match()という箇所で一応言及はしているのだが、最初に見た人がここにたどり着くのは難しい。
同じ公式ドキュメントなら、以下のほうがオススメである。
正規表現 HOWTO ? Python 3.6.5 ドキュメント
  1. 2018/07/01(日) 22:18:41|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0

scikit-learnとTensorFlowによる実践機械学習 輪読会4章
2018/06/24(日) 00:40:00

2018/06/15(金)に、scikit-learnとTensorFlowによる実践機械学習輪読会#4で発表してきた。

scikit-learnとTensorFlowによる実践機械学習/原題:Hands-On Machine Learning with Scikit-Learn and TensorFlow」の4.1 - 4.2の説明を担当した。資料はこちら!



勾配降下法の3つの方式:バッチ勾配降下法、確率的勾配降下法、ミニバッチ勾配降下法



この本では4.2.1でバッチ勾配降下法、4.2.2で確率的勾配降下法を扱い、その後の4.2.3でミニバッチ勾配降下法を取り扱っている。

scikit-learn_42.jpg

この順序で話が進むので、3種類の方法の関連性や相違点を把握しやすかった。

「関連性や相違点」を具体的に挙げると、「ミニバッチ勾配降下法はバッチと確率的の中間の特徴を持つ」という点である。また、ミニバッチでバッチサイズが1の特殊な場合が確率的勾配降下法であり、バッチサイズが全体の特殊な場合がバッチ学習である、という見かたもできると気づいた。

今までの理解では、「どうやら通常はミニバッチを使うらしい」ということは分かっていた。しかし、すべてのインスタンスについて勾配を計算して学習するバッチ学習と比べて、どう違うのかがきちんと理解できていなかった。

scikit-learnとTensorFlowによる実践機械学習」ではまずバッチ勾配降下法を説明して、その後で確率的勾配降下法が出てくる。その中で確率的の方は
・1回のイテレーションが高速
・アウトオブコア(=メモリに乗りきらないデータ)に対応している
・最適解で止まることがない
といった特徴があることに触れている。
また、4.2節の最後にはアルゴリズムの比較表があり、4.1と4.2の全体を見渡して概要をつかむことができる。全体的に説明の流れが上手いと感じた。

インスタンスの選ぶ方法による収束速度の違いについて


輪読の最中に「本に書いてある内容が分からない」と話題になった箇所がある。

P.120
(筆者補足:確率的勾配降下法では)インスタンスが無作為に選ばれるため、一部のインスタンスはエポックの中で複数回選ばれることがあるのに対し、ほかのインスタンスは全然選ばれないことがあることに注意しよう。各インスタンスですべてのインスタンスを処理するようにしたければ、訓練セットをシャッフルしてからインスタンスを逐次的に取り出し、終わったら再びシャッフルするという方法もある。しかし、この方法は、一般に収束まで余分に時間がかかる。
(※太字は筆者による)



本では、確率的勾配降下法でインスタンスを選ぶとき、2通りの選び方があるよ、と言っている。
1つ目は、毎回ランダムに選ぶ方法である。例えばインスタンスが5個で、1~5の番号がついているとしよう。(普通はもっと多いが、説明のため簡単にする。)選び方の例は以下のようになる。毎回、1~5の中からランダムで1つの数を選んでいる。

3, 5, 4, 3, 4, 2, 4, 1, 3, 4, 4, 3, 1, 2, 4, ……

2つ目は、インスタンスの集合を一度シャッフルして取り出して、終わったら再度シャッフルする、という方法である。さっきの例でいえば、選び方の例は以下のようになる。分かりやすいように5つごとにカッコでまとめた。カッコの中が1~5の並び替えになっている。

[2, 3, 1, 4, 5], [3, 5, 4, 1, 2], [1, 4, 2, 3, 5], ……

この2つの選び方では収束の速度に差があり、前者が速くて後者が遅いらしい。何でだろう?
直感的には、ランダムで選ぶ限り、どのような選び方だろうと収束速度に差は無いように思える。
輪読会に来ている方が知っているかなと思ったが、誰もその理由を知らないようだった。重要な箇所ではないからそれほど気に留めなくても良いとは思うが、ちょっと気になる。

GitHub上のサンプルコードについて



ありがたいことに、本に掲載されているコードはGitHub(下記)に上がっている。
GitHub - ageron/handson-ml: A series of Jupyter notebooks that walk you through the fundamentals of Machine Learning and Deep Learning in python using Scikit-Learn and TensorFlow.

残念ながら、スライドを作る方で手一杯だったので、
GitHub上のコードを見たりダウンロード・実行するところまで手が回らなかった。反省である。

ソースコードは全体的に平易であり、本の内容が理解できていればそれを素直にコードに直したものである。
とはいえ、コードが書けなきゃ実際の機械学習処理ができないので手を動かさなきゃいけない。
俺はコーディングよりも理論の方についつい寄ってしまうので、気をつけなければ……

それでは。
  1. 2018/06/24(日) 00:40:00|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0

kaggle初心者はカーネルを読むだけでも勉強になったよ
2018/06/17(日) 20:59:31

はじめに



機械学習を少しずつ勉強している。
その中で先月kaggleに登録して、そこから少しずつkernelを写して書いている。
「このやり方、結構いいんじゃないか」と思ったので、kaggleのkernelの良さについて書く。

対象読者



「kaggle登録はしたけどどうすればいいかよく分からん」
「いきなり問題を解けといったって、いい解法が思いつかない」
くらいの人を想定しています。
kaggleのコンペティションにガンガン出て順位を競っているような人は対象外です。

Kernelとは何か?



少し分かりにくいところにあるが、kaggle公式では以下のように説明されている。
Titanic: Machine Learning from Disaster | Kaggle

What are kernels?
Kaggle Kernels is a cloud computational environment that enables reproducible and collaborative analysis. Kernels supports scripts in R and Python, Jupyter Notebooks, and RMarkdown reports.

拙訳:
kernelとは何ですか?
Kaggle Kernelは、クラウド上の計算環境であり、再現性のある共同の解析ができます。RとPythonのスクリプト、Jupyter Notebook、そしてRMarkdown reportをサポートしています。

pythonに限れば、kaggle上でJupyter Notebook形式でコードを書いて実行することができる。
また、ここに他の参加者がソースコードを投稿・公開している。
上手い人のコードを読んで参考にすることができるというわけだ。

このkernelを見て学習をするメリットは以下のとおりである。

利点1:Pythonの各種ライブラリの実用的な使い方がわかる



俺自身はPythonを普段あまり使っていないので、文法や関数が分からないこともある。
たまにRubyの書き方をしてしまったりするし。
そもそもライブラリをどう使うか、どういったことが可能なのか、という知識があまりない。
機械学習をやっていく上では、Numpy・Pandas・Matplotlibなどのライブラリは避けて通れない。
機械学習の勉強を進めるときは素のpythonだけではなく、これらのライブラリも使えるようにならなければいけない。何種類かのライブラリの知識も必要になるという点は、ちょっとハードルが高いと思う。

kaernel上で、実際で使われているのを見ることで
「pandasってこういうことができるんだな」「numpyのこの関数ってこう使うのか」と分かる。
もちろんライブラリの公式ドキュメントを順番に見ても使い方を学ぶことはできると思うが、
しかしそれだと滅多に使わないものまで出てきてしまう。
実践に即した知識を習得できるのが良い点かと思う。

利点2:問題の解き方がわかる


kaggleでは機械学習のコンペティションが開催されている。
しかし「はい、これが問題です、解いてください」と言われても、初心者は解けないわけだ。
どういう解法でどういうパラメータを設定して解けば上手くいくかなんて分からないからである。

そしてある特定のアルゴリズムで解いてみようとしても、コードが上手く動かなくてエラーが出たりして、
「え、どこで間違えたんだ、分からない、困った」ということになる。
「解法が分からなくて詰む」「解法が分かってもコードが書けなくて詰む」の二重苦である。

SIGNATE(旧名:DeepAnalytics)というkaggleの日本語版のようなサイトがあり、同様にコンペティションが開催されている。
俺は3月に、初めてコンペティションに参加して
「取りあえず思いついた解法で解いて提出してみるか、きっと酷いスコアだろうけど」と思ってゼロから書き始め、
数多のエラーを喰らった末に疲労困憊しながら提出したが、予想していた以上に酷いスコアだった。
もちろん手を動かしたぶんの実力がついたとは思うが、しかし技術力をつける上では遠回りだった。

そこでkernelの出番である。

・(Jupyter Notebook形式の場合は)手法の説明+コードがある
・ちゃんと動くコードなので、エラーにハマらずに済む
・自分のkernelにコピー(fork)して動かせる
・そこから少しずつ書き換えてみて、どうなるかな、と試してみることも可能
といった利点がある。

なお、機械学習の初心者ではなく実力者であっても、
素晴らしく上手く解ける方法を最初から分かっているとは限らないので、
kernelに掲載された解法を参考にしているようだ。
以下の記事を参照。
Kaggleを取り掛かるまでにやったこととと、モチベーションの維持のために必要だったこと - にほんごのれんしゅう

どのkernelから見れば良いの?



コンペティションを決めていて、それに関する良い感じのkernelを探す場合は
ひとまずはVote数でソートすれば良さそうだ。
「このkerelは参考になった」と思った人がVote(投票)するので、Vote数の順にすれば人気のあるkernelを見られる。
(下の図の赤い四角の部分)

20180616_kaggle-kernels.png

投票数の多く人気のあるkernelの中でもどれを選ぶか、という点については、
タイトルやタグ名から以下のことが読み取れるので、それを参考に決めれば良いだろう。

・EDA:「Exploratory Data Analysis」の略、日本語に訳すと「探索的データ解析」となる。分かりやすくいうと「問題を解くより前に、入力として与えられたデータがどのようなものか、表やグラフに可視化しながら観察してみよう」くらいのニュアンスである。したがってこのタイトル/タグがある場合、問題そのものを解いていない場合が多い。
・解法名:「特定の解法を使って解いてるコードを見たいんだよなぁ」という場合にはそのアルゴリズムの名前があるものを選べばよい。
・スコア:そのkernelのコードを実行したときのスコアを表す。例えば上の図で上から2番目のkernelには「0.735」というタグが付いているので、submitすればそのスコアになるはずである。



参考・関連



kaggle初心者に向いている、kaggle内のコンテンツ、という切り口で考えると

Titanic コンペティションのtutorialをやる
Learn(機械学習やPandasやRなどの教材)をやる
あたりも良いだろう。

それでは。
  1. 2018/06/17(日) 20:59:31|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0

機械学習用GPUインスタンスのpaperspaceに利用申請しても承認されない
2018/05/30(水) 00:15:22

paperspaceはGPUインスタンスを利用できるサービスである。仮想デスクトップ環境を備えている。
機械学習・データ分析のために使うほか、ゲームを目的に使っている人もいるようだ。

fast.aiを作ったJeremy Howardも、フォーラムのこのページで"We’re currently recommending Paperspace as the best option for this course"(fast.aiのコースの最良の選択肢としてお勧めしています)と、paperspaceの使用を勧めている。
AWSやGCPとの違いはよく分かっていないけど。

fast.ai用のpaperspaceのセットアップ方法は以下に書いてある。
fastai_deeplearn_part1/paperspace.md at master · reshamas/fastai_deeplearn_part1 · GitHub

高性能なGPUを使用するためには、管理者に使用の理由を申請する必要があるみたいだ。
そうするとpaperspace側から承認のメールが届いて、使えるようになるらしい。
というわけで、5月25日の夜に「fast.aiの講座で使用するため」と書いて申請を出した。
……。
…………。
全然承認が下りない……何の音沙汰もない!!
もう4日も経ってるんですけど。土日は休みなのかなとか思ったけど、平日も全然返答をしないってどういうことなの。
ちょいと「paperspace」でTwitterを検索してみると、同様の声が少なからず見つかった。








公式アカウントがリプライしていることもある。



"you'll get an email as soon as your request is approved"ってちょっと返事が酷くないですか。
いつになっても承認されなくて困ってるんだから、何も説明していないに等しいと思うんだけど……

うーん、機械学習の勉強をやろうとすると環境構築で行き詰まるの、何とかならないかなぁ……
それでは。
  1. 2018/05/30(水) 00:15:22|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0
次のページ

FC2Ad