rabbit-slide-kou-nagoya-rubykaigi-03 2017.2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rabbit +1 -0
- data/README.rd +81 -0
- data/Rakefile +18 -0
- data/apache-arrow-gi-based-ruby-bindings.rab +766 -0
- data/config.yaml +27 -0
- data/data/hebi.svg +1108 -0
- data/data/hebi_blue.svg +1110 -0
- data/data/panda_kotatsu.svg +78 -0
- data/examples/data/bow.data.tf.filtered +0 -0
- data/examples/data/bow.data.tf.raw +0 -0
- data/examples/data/bow.data.tfidf.filtered +0 -0
- data/examples/data/bow.data.tfidf.raw +0 -0
- data/examples/data/bow.metadata.tf.filtered +1 -0
- data/examples/data/bow.metadata.tf.raw +1 -0
- data/examples/data/bow.metadata.tfidf.filtered +1 -0
- data/examples/data/bow.metadata.tfidf.raw +1 -0
- data/examples/data/topics.tf.filtered +0 -0
- data/examples/data/topics.tf.raw +0 -0
- data/examples/data/topics.tfidf.filtered +0 -0
- data/examples/data/topics.tfidf.raw +0 -0
- data/examples/estimate-topics.py +72 -0
- data/examples/raw-show-related-terms.rb +38 -0
- data/examples/raw-write-bow.rb +124 -0
- data/examples/read.rb +30 -0
- data/examples/run.sh +33 -0
- data/examples/show-related-terms.rb +39 -0
- data/examples/show.sh +20 -0
- data/examples/write-bow.rb +96 -0
- data/examples/write.py +15 -0
- data/images/clear-code.svg +161 -0
- data/images/copy-data-between-system.png +0 -0
- data/images/groonga-logo.svg +118 -0
- data/images/rroonga-logo.svg +117 -0
- data/images/share-data-between-system.png +0 -0
- data/images/system-with-ruby.png +0 -0
- data/pdf/nagoya-rubykaigi-03-apache-arrow-gi-based-ruby-bindings.pdf +0 -0
- data/theme.rb +6 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 00c1978e0d471f1f32ece9d0fba6f7c5685a5e9f
|
4
|
+
data.tar.gz: 1bde6cf49d82a6bb4b26ee8845da9bd90b0622e1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f6696d3b16024c5e3c3f94282579414a1481b2f05274f91e27e2583c988628c157b0d1b1883abc69d5758ea7e70f4a9cb23149acf734f719e587f8ba607293f
|
7
|
+
data.tar.gz: ae574cf6d48bf431660f2d69e2bc25a331f2bb720ad492d9da3801a62a24b81adc30be06c3891582f7ee6d81efd76be0e095e7414309d7a69fa4b63ae99c2a3b
|
data/.rabbit
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
apache-arrow-gi-based-ruby-bindings.rab
|
data/README.rd
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
= Apache ArrowのRubyバインディングをGObject Introspectionで
|
2
|
+
|
3
|
+
Apache Arrowはデータ分析を支援するライブラリーです。高速にデータにアクセスできる機能を提供します。重要なのは既存の多くのデータ分析関連プロダクトがApache Arrowと連携すると表明しているところです。RubyでもApache Arrowを使えるようになるとRubyでも既存のデータ分析関連プロダクトと連携できるようになります。そうなれるようにGObject Introspectionを使ってRubyからApache Arrowを使えるようにする方法を紹介します。
|
4
|
+
|
5
|
+
== ライセンス
|
6
|
+
|
7
|
+
=== スライド
|
8
|
+
|
9
|
+
CC BY-SA 4.0
|
10
|
+
|
11
|
+
原著作者名は以下の通りです。
|
12
|
+
|
13
|
+
* 須藤功平(またはKouhei Sutou)
|
14
|
+
|
15
|
+
=== 画像
|
16
|
+
|
17
|
+
==== Apache Arrow関連の画像
|
18
|
+
|
19
|
+
以下の画像がApache Arrow関連の画像です。
|
20
|
+
|
21
|
+
* images/copy-data-between-system.png
|
22
|
+
* images/share-data-between-system.png
|
23
|
+
* images/system-with-ruby.png
|
24
|
+
|
25
|
+
Apache License 2.0
|
26
|
+
|
27
|
+
Copyright 2016 The Apache Software Foundation
|
28
|
+
|
29
|
+
==== Groonga関連の画像
|
30
|
+
|
31
|
+
以下の画像がGroonga関連の画像です。
|
32
|
+
|
33
|
+
* images/groonga-logo.svg
|
34
|
+
* images/rroonga-logo.svg
|
35
|
+
|
36
|
+
CC BY 3.0
|
37
|
+
|
38
|
+
原著作者名は以下の通りです。
|
39
|
+
|
40
|
+
* Groongaプロジェクト
|
41
|
+
|
42
|
+
==== クリアコード関連の画像
|
43
|
+
|
44
|
+
以下の画像がクリアコード関連の画像です。
|
45
|
+
|
46
|
+
* images/clear-code.svg
|
47
|
+
|
48
|
+
CC BY-SA 4.0
|
49
|
+
|
50
|
+
原著作者名は以下の通りです。
|
51
|
+
|
52
|
+
* クリアコード
|
53
|
+
|
54
|
+
==== その他の画像
|
55
|
+
|
56
|
+
CC BY-SA 4.0
|
57
|
+
|
58
|
+
原著作者名は以下の通りです。
|
59
|
+
|
60
|
+
* 須藤功平(またはKouhei Sutou)
|
61
|
+
|
62
|
+
== 作者向け
|
63
|
+
|
64
|
+
=== 表示
|
65
|
+
|
66
|
+
rake
|
67
|
+
|
68
|
+
=== 公開
|
69
|
+
|
70
|
+
rake publish
|
71
|
+
|
72
|
+
== 閲覧者向け
|
73
|
+
|
74
|
+
=== インストール
|
75
|
+
|
76
|
+
gem install rabbit-slide-kou-nagoya-rubykaigi-03
|
77
|
+
|
78
|
+
=== 表示
|
79
|
+
|
80
|
+
rabbit rabbit-slide-kou-nagoya-rubykaigi-03.gem
|
81
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rabbit/task/slide"
|
2
|
+
|
3
|
+
# Edit ./config.yaml to customize meta data
|
4
|
+
|
5
|
+
spec = nil
|
6
|
+
Rabbit::Task::Slide.new do |task|
|
7
|
+
spec = task.spec
|
8
|
+
spec.files += Dir.glob("examples/**/*.*")
|
9
|
+
# spec.files += Dir.glob("doc/**/*.*")
|
10
|
+
# spec.files -= Dir.glob("private/**/*.*")
|
11
|
+
spec.add_runtime_dependency("rabbit-theme-clear-code")
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Tag #{spec.version}"
|
15
|
+
task :tag do
|
16
|
+
sh("git", "tag", "-a", spec.version.to_s, "-m", "Publish #{spec.version}")
|
17
|
+
sh("git", "push", "--tags")
|
18
|
+
end
|
@@ -0,0 +1,766 @@
|
|
1
|
+
= Apache Arrowの\nRubyバインディングを\nGObject Introspectionで
|
2
|
+
|
3
|
+
: author
|
4
|
+
須藤功平
|
5
|
+
: institution
|
6
|
+
株式会社クリアコード
|
7
|
+
: content-source
|
8
|
+
名古屋Ruby会議03
|
9
|
+
: date
|
10
|
+
2017-02-11
|
11
|
+
: allotted-time
|
12
|
+
50m
|
13
|
+
: theme
|
14
|
+
.
|
15
|
+
|
16
|
+
= 内容
|
17
|
+
|
18
|
+
(1) まくら
|
19
|
+
(2) 本題
|
20
|
+
(3) オチ
|
21
|
+
|
22
|
+
= やりたいこと
|
23
|
+
|
24
|
+
Rubyで\n
|
25
|
+
データ分析
|
26
|
+
|
27
|
+
= データ分析?
|
28
|
+
|
29
|
+
いろいろある
|
30
|
+
|
31
|
+
= やりたいデータ分析
|
32
|
+
|
33
|
+
(('tag:center'))
|
34
|
+
全文検索関連
|
35
|
+
|
36
|
+
* 同義語・関連語の自動抽出\n
|
37
|
+
例:整数とIntegerは同じ
|
38
|
+
* 最近アツいキーワードの抽出
|
39
|
+
* ...
|
40
|
+
|
41
|
+
= 課題
|
42
|
+
|
43
|
+
* 道具が足りない
|
44
|
+
* ライブラリーがない・\n
|
45
|
+
メンテナンスされていない
|
46
|
+
* 道具が使いにくい
|
47
|
+
|
48
|
+
= 解決方法
|
49
|
+
|
50
|
+
やる\n
|
51
|
+
(('note:(道具を整備する)'))
|
52
|
+
|
53
|
+
= 世間の様子
|
54
|
+
|
55
|
+
* 主にJavaとPythonを使う
|
56
|
+
* 道具が揃っている
|
57
|
+
* 組み合わせてデータ分析
|
58
|
+
|
59
|
+
= 組み合わせた様子
|
60
|
+
|
61
|
+
# image
|
62
|
+
# src = images/copy-data-between-system.png
|
63
|
+
# relative_width = 100
|
64
|
+
|
65
|
+
(('note:https://arrow.apache.org/より(Apache License 2.0)'))
|
66
|
+
|
67
|
+
= 組み合わせの課題
|
68
|
+
|
69
|
+
* データ交換コストが高い
|
70
|
+
* データの直列化でCPUの8割を使用\n
|
71
|
+
by https://arrow.apache.org/
|
72
|
+
|
73
|
+
= 解決方法
|
74
|
+
|
75
|
+
データの\n
|
76
|
+
フォーマットを\n
|
77
|
+
統一しよう!
|
78
|
+
|
79
|
+
= 統一した様子
|
80
|
+
|
81
|
+
# image
|
82
|
+
# src = images/share-data-between-system.png
|
83
|
+
# relative_width = 100
|
84
|
+
|
85
|
+
(('note:https://arrow.apache.org/より(Apache License 2.0)'))
|
86
|
+
|
87
|
+
= これはチャンス!
|
88
|
+
|
89
|
+
* RubyがArrow対応すると…
|
90
|
+
* 既存のシステムとやりとりできる
|
91
|
+
* 「この部分だけはRubyを使う」を\n
|
92
|
+
できる
|
93
|
+
|
94
|
+
= 一部でRuby
|
95
|
+
|
96
|
+
# image
|
97
|
+
# src = images/system-with-ruby.png
|
98
|
+
# relative_width = 100
|
99
|
+
|
100
|
+
(('note:前述の図を変更(Apache License 2.0)'))
|
101
|
+
|
102
|
+
= 一部でRubyを…使える?
|
103
|
+
|
104
|
+
道具が\n
|
105
|
+
ないじゃん!
|
106
|
+
|
107
|
+
= 道具
|
108
|
+
|
109
|
+
# image
|
110
|
+
# src = images/rroonga-logo.svg
|
111
|
+
# relative_width = 100
|
112
|
+
|
113
|
+
(('note:Groongプロジェクト(CC BY 3.0)'))
|
114
|
+
|
115
|
+
= Rroonga
|
116
|
+
|
117
|
+
* 全文検索エンジン((*ライブラリー*))
|
118
|
+
* SQLで操作とかじゃなく\n
|
119
|
+
((*オブジェクト*))として触れる
|
120
|
+
|
121
|
+
= オブジェクト例
|
122
|
+
|
123
|
+
転置索引\n
|
124
|
+
オブジェクト
|
125
|
+
|
126
|
+
= 転置索引
|
127
|
+
|
128
|
+
(('tag:center'))
|
129
|
+
雑な説明
|
130
|
+
|
131
|
+
* (({Hash}))みたいなもの
|
132
|
+
* キー:
|
133
|
+
* トークン(単語みたいなもの)
|
134
|
+
* 値:
|
135
|
+
* キー(トークン)を含む文書の一覧
|
136
|
+
|
137
|
+
= 転置索引オブジェクト(1)
|
138
|
+
|
139
|
+
# coderay ruby
|
140
|
+
|
141
|
+
index = Groonga["Words.index"]
|
142
|
+
token = "オブジェクト"
|
143
|
+
p index.estimate_size(token)
|
144
|
+
# => 19048
|
145
|
+
# 「オブジェクト」を含む文書は
|
146
|
+
# 約19048個ありそう
|
147
|
+
|
148
|
+
= 転置索引オブジェクト(2)
|
149
|
+
|
150
|
+
# coderay ruby
|
151
|
+
|
152
|
+
index.open_cursor(token) do |cursor|
|
153
|
+
# 最初の出現情報
|
154
|
+
posting = cursor.next
|
155
|
+
# 「オブジェクト」を含む最初の文書のID
|
156
|
+
p posting.record.id # => 17
|
157
|
+
# この文書が何個「オブジェクト」を含むか
|
158
|
+
p posting.term_frequency # => 1
|
159
|
+
# 文書の内容
|
160
|
+
puts posting.record.document
|
161
|
+
end
|
162
|
+
|
163
|
+
= 分析に使ってみよう
|
164
|
+
|
165
|
+
るりまを分析\n
|
166
|
+
↓\n
|
167
|
+
関連語を抽出
|
168
|
+
|
169
|
+
= 関連語の抽出方法例
|
170
|
+
|
171
|
+
(1) 文書を前処理
|
172
|
+
(2) 全文書をトピックに分類\n
|
173
|
+
* どんなトピックがあるかは学習
|
174
|
+
(3) 同じトピックで使われやすい\n
|
175
|
+
単語を抽出\n
|
176
|
+
→関連語!
|
177
|
+
|
178
|
+
= 文書の前処理
|
179
|
+
|
180
|
+
単語の出現頻度\n
|
181
|
+
(('note:(Bag of Wordsという)'))\n
|
182
|
+
に変換
|
183
|
+
|
184
|
+
= 単語の出現頻度
|
185
|
+
|
186
|
+
# coderay ruby
|
187
|
+
"名古屋マジ名古屋"
|
188
|
+
# ↓
|
189
|
+
{
|
190
|
+
"名古屋" => 2, # 2回
|
191
|
+
"マジ" => 1, # 1回
|
192
|
+
}
|
193
|
+
|
194
|
+
= 単語は数値に変換
|
195
|
+
|
196
|
+
# coderay ruby
|
197
|
+
|
198
|
+
# "名古屋" => 10
|
199
|
+
# "マジ" => 20
|
200
|
+
{
|
201
|
+
10 => 2, # 「名古屋」2回
|
202
|
+
20 => 1, # 「マジ」1回
|
203
|
+
}
|
204
|
+
|
205
|
+
= なんで数値にするの?
|
206
|
+
|
207
|
+
計算しやすい
|
208
|
+
|
209
|
+
= Rroongaで前処理できる?
|
210
|
+
|
211
|
+
* 出現回数は求められる?
|
212
|
+
* 👌:(({posting.term_frequency}))
|
213
|
+
* 単語を数値に変換できる?
|
214
|
+
* 👌:全文検索エンジンの必須機能
|
215
|
+
|
216
|
+
= Rroongaで前処理(1)
|
217
|
+
|
218
|
+
# coderay ruby
|
219
|
+
|
220
|
+
bow = {} # 「名古屋」の分だけ
|
221
|
+
index.open_cursor("名古屋") do |cursor|
|
222
|
+
cursor.each do |posting|
|
223
|
+
record_id = posting.record_id
|
224
|
+
term_id = posting.term_id # "名古屋"のID
|
225
|
+
term_frequency = posting.term_frequency # 出現回数
|
226
|
+
bow[record_id] ||= {}
|
227
|
+
bow[record_id][term_id] = term_frequency
|
228
|
+
# bow: { # ↓実際は文字列じゃなくてID
|
229
|
+
# 2 => {"名古屋" => 9} # 文書2では9回出現
|
230
|
+
# 5 => {"名古屋" => 19} # 文書5では19回出現
|
231
|
+
# }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
= Rroongaで前処理(2)
|
236
|
+
|
237
|
+
# coderay ruby
|
238
|
+
|
239
|
+
bow = {}
|
240
|
+
index.table.each do |token| # 全トークンを処理
|
241
|
+
index.open_cursor(token) do |cursor|
|
242
|
+
cursor.each do |posting|
|
243
|
+
# ...同じ...
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
# bow: { # 完成!
|
248
|
+
# 2 => {"名古屋" => 9, "マジ" => 2}
|
249
|
+
# 5 => {"名古屋" => 19, "寄席" => 1},
|
250
|
+
# ...
|
251
|
+
# }
|
252
|
+
|
253
|
+
= 前処理終わり
|
254
|
+
|
255
|
+
* 次はトピックに分類
|
256
|
+
* どんなトピックがあるかは学習
|
257
|
+
|
258
|
+
= トピックの学習方法
|
259
|
+
|
260
|
+
(('tag:center'))
|
261
|
+
(('tag:x-large'))
|
262
|
+
LDA\n
|
263
|
+
(('note:(Latent Dirichlet Allocation/潜在的ディリクレ配分法)'))
|
264
|
+
|
265
|
+
(('note:他にも色々ある'))\n
|
266
|
+
(('note:参考:http://www.ism.ac.jp/~daichi/lectures/H24-TopicModel/ISM-2012-TopicModels-daichi.pdf'))
|
267
|
+
|
268
|
+
= RubyでLDA
|
269
|
+
|
270
|
+
lda-ruby gem
|
271
|
+
|
272
|
+
= RubyでLDAをしない!
|
273
|
+
|
274
|
+
なぜなら!\n
|
275
|
+
Apache Arrowとか\n
|
276
|
+
GObject Introspectionの\n
|
277
|
+
話をする\n
|
278
|
+
機会がなくなるからだ!
|
279
|
+
|
280
|
+
= PythonでLDA
|
281
|
+
|
282
|
+
scikit-learn\n
|
283
|
+
(('note:(gensimの方がよく使われているかも)'))
|
284
|
+
|
285
|
+
= scikit-learnでLDA
|
286
|
+
|
287
|
+
# coderay python
|
288
|
+
import sklearn.decomposition
|
289
|
+
LDA = sklearn.decomposition.LatentDirichletAllocation
|
290
|
+
model = LDA(n_topics=100, # 100トピックに分類
|
291
|
+
learning_method="online",
|
292
|
+
total_samples=len(bag_of_words)) # 文書数
|
293
|
+
for words in bag_of_words: # 前処理結果
|
294
|
+
model.partial_fit(words) # 要フォーマット変換
|
295
|
+
model.components_ # ここに学習したトピックがある
|
296
|
+
|
297
|
+
= 前処理結果がない!
|
298
|
+
|
299
|
+
* 前処理はRubyでやった
|
300
|
+
* Python側にはない
|
301
|
+
* 前処理結果がないと\n
|
302
|
+
scikit-learnで分析できない!
|
303
|
+
* どうしよう!
|
304
|
+
* (('wait'))そうだ!Apache Arrowだ!
|
305
|
+
|
306
|
+
= Arrowでつながる世界
|
307
|
+
|
308
|
+
# image
|
309
|
+
# src = images/system-with-ruby.png
|
310
|
+
# relative_width = 100
|
311
|
+
|
312
|
+
(('note:(Apache License 2.0)'))
|
313
|
+
|
314
|
+
= RubyでArrow
|
315
|
+
|
316
|
+
* ArrowはC++のライブラリー
|
317
|
+
* Rubyからは使えない
|
318
|
+
* どうしよう!
|
319
|
+
* (('wait'))やる(バインディングを作る)
|
320
|
+
|
321
|
+
= Arrowのバインディング
|
322
|
+
|
323
|
+
* arrow-glib
|
324
|
+
* github.com/kou/arrow-glib
|
325
|
+
* Arrowのラッパー・C APIを提供
|
326
|
+
* GObject Introspection対応
|
327
|
+
* バインディングを実行時に生成
|
328
|
+
|
329
|
+
= 使い方:準備
|
330
|
+
|
331
|
+
# coderay ruby
|
332
|
+
require "gi"
|
333
|
+
Arrow = GI.load("Arrow")
|
334
|
+
|
335
|
+
= 使い方:配列を作る
|
336
|
+
|
337
|
+
# coderay ruby
|
338
|
+
|
339
|
+
# Arrowは高速に1次元・2次元配列を
|
340
|
+
# 扱うAPIを提供するライブラリー
|
341
|
+
builder = Arrow::UInt32ArrayBuilder.new
|
342
|
+
builder.append(29) # 要素追加
|
343
|
+
builder.append(9) # 要素追加
|
344
|
+
term_ids = builder.finish # 配列作成
|
345
|
+
p term_ids.length # => 2
|
346
|
+
p term_ids.get_value(0) # => 29
|
347
|
+
p term_ids.get_value(1) # => 9
|
348
|
+
|
349
|
+
= 少し…使いにくい!
|
350
|
+
|
351
|
+
* GObject Introspection
|
352
|
+
* だいたいいい感じになる!(('note:(すごい!)'))
|
353
|
+
* が!Ruby特有のところは一手間必要
|
354
|
+
|
355
|
+
= 使いやすさ検討
|
356
|
+
|
357
|
+
# coderay ruby
|
358
|
+
|
359
|
+
builder = Arrow::UInt32ArrayBuilder.new
|
360
|
+
builder.append(29)
|
361
|
+
builder.append(9)
|
362
|
+
term_ids = builder.finish
|
363
|
+
# ↓
|
364
|
+
term_ids =
|
365
|
+
Arrow::UInt32ArrayBuilder.build([29, 9])
|
366
|
+
|
367
|
+
= 一手間
|
368
|
+
|
369
|
+
# coderay ruby
|
370
|
+
class Arrow::ArrayBuilder
|
371
|
+
class << self
|
372
|
+
def build(values)
|
373
|
+
builder = new
|
374
|
+
values.each do |value|
|
375
|
+
builder.append(value)
|
376
|
+
end
|
377
|
+
builder.finish
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
= もう一手間
|
383
|
+
|
384
|
+
# coderay ruby
|
385
|
+
|
386
|
+
class Arrow::UInt32Array
|
387
|
+
class << self
|
388
|
+
def new(values)
|
389
|
+
UInt32ArrayBuilder.build(values)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
= 一手間後
|
395
|
+
|
396
|
+
# coderay ruby
|
397
|
+
|
398
|
+
builder = Arrow::UInt32ArrayBuilder.new
|
399
|
+
builder.append(29)
|
400
|
+
builder.append(9)
|
401
|
+
term_ids = builder.finish
|
402
|
+
# ↓
|
403
|
+
term_ids = Arrow::UInt32Array.new([29, 9])
|
404
|
+
|
405
|
+
= さらに使いやすさ検討
|
406
|
+
|
407
|
+
# coderay ruby
|
408
|
+
|
409
|
+
p term_ids.get_value(0) # => 29
|
410
|
+
p term_ids.get_value(1) # => 9
|
411
|
+
# ↓
|
412
|
+
p term_ids[0] # => 29
|
413
|
+
p term_ids[1] # => 9
|
414
|
+
|
415
|
+
= 二手間
|
416
|
+
|
417
|
+
# coderay ruby
|
418
|
+
class Arrow::Array
|
419
|
+
def [](i)
|
420
|
+
get_value(i)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
= もう一手間
|
425
|
+
|
426
|
+
# coderay ruby
|
427
|
+
class Arrow::Array
|
428
|
+
include Enumerable
|
429
|
+
def each
|
430
|
+
length.times do |i|
|
431
|
+
yield(self[i])
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
= 二手間後
|
437
|
+
|
438
|
+
# coderay ruby
|
439
|
+
|
440
|
+
p term_ids.get_value(0) # => 29
|
441
|
+
p term_ids.get_value(1) # => 9
|
442
|
+
# ↓
|
443
|
+
p term_ids.to_a # => [29, 9]
|
444
|
+
|
445
|
+
= 一手間はどこに書くの?
|
446
|
+
|
447
|
+
# coderay ruby
|
448
|
+
|
449
|
+
# こう?
|
450
|
+
require "gi"
|
451
|
+
Arrow = GI.load("Arrow")
|
452
|
+
module Arrow
|
453
|
+
class Array
|
454
|
+
# ...
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
= 違う!
|
459
|
+
|
460
|
+
* (({GI.load}))はデモ用のAPI
|
461
|
+
* ちゃんと作るときは使わない
|
462
|
+
* (({GI::Loader}))を継承
|
463
|
+
* (({#post_load}))フック時に一手間
|
464
|
+
|
465
|
+
= (({GI::Loader#post_load}))
|
466
|
+
|
467
|
+
# coderay ruby
|
468
|
+
|
469
|
+
class Arrow::Loader < GI::Loader
|
470
|
+
private
|
471
|
+
def post_load(*args)
|
472
|
+
require "arrow/array"
|
473
|
+
require "arrow/array-builder"
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
= (({arrow/array.rb}))
|
478
|
+
|
479
|
+
# coderay ruby
|
480
|
+
|
481
|
+
class Arrow::Array
|
482
|
+
include Enumerable
|
483
|
+
def each
|
484
|
+
length.times do |i|
|
485
|
+
yield(self[i])
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
= (({arrow.rb}))
|
491
|
+
|
492
|
+
# coderay ruby
|
493
|
+
|
494
|
+
require "arrow/loader"
|
495
|
+
module Arrow
|
496
|
+
Loader.load("Arrow", self)
|
497
|
+
# ↑の中で#post_loadが呼ばれる
|
498
|
+
end
|
499
|
+
|
500
|
+
= 使い方
|
501
|
+
|
502
|
+
# coderay ruby
|
503
|
+
|
504
|
+
require "arrow"
|
505
|
+
|
506
|
+
term_ids = Arrow::UInt32Array.new([29, 9])
|
507
|
+
p term_ids.to_a # => [29, 9]
|
508
|
+
|
509
|
+
= すごい!
|
510
|
+
|
511
|
+
Rubyっぽい!
|
512
|
+
|
513
|
+
= 実装
|
514
|
+
|
515
|
+
* RArrow
|
516
|
+
* github.com/kou/rarrow
|
517
|
+
* (('note:RのArrowバインディングみたいでアレかもしれない'))
|
518
|
+
* 他の一手間例もアリ
|
519
|
+
* 例:(({.open {|io| ...}}))で自動(({close}))
|
520
|
+
|
521
|
+
= 前処理結果を渡す
|
522
|
+
|
523
|
+
* 忘れていたでしょ?
|
524
|
+
* Arrowの話をしていたのはこのため
|
525
|
+
* 手順
|
526
|
+
(1) Rubyで書き出し
|
527
|
+
(2) Pythonで読み込み
|
528
|
+
|
529
|
+
= Rubyで書き出し
|
530
|
+
|
531
|
+
# coderay ruby
|
532
|
+
|
533
|
+
FOS = Arrow::IO::FileOutputStream # 長いから
|
534
|
+
SW = Arrow::IPC::StreamWriter # 長いから
|
535
|
+
FOS.open("/tmp/bow", false) do |output_stream|
|
536
|
+
# schema:カラム名と型の定義(省略)
|
537
|
+
SW.open(output_stream, schema) do |writer|
|
538
|
+
bow.each do |record_id, words|
|
539
|
+
# record_batch(省略):
|
540
|
+
# テーブルからN行だけ抜き出したもの
|
541
|
+
writer.write_record_batch(record_batch)
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
= Pythonで読み出し
|
547
|
+
|
548
|
+
# coderay python
|
549
|
+
|
550
|
+
from scipy.sparse import csr_matrix
|
551
|
+
import pandas as pd
|
552
|
+
import pyarrow as A
|
553
|
+
with A.io.MemoryMappedFile("/tmp/bow", "rb") as source:
|
554
|
+
reader = A.ipc.StreamReader(source)
|
555
|
+
for record_batch in reader: # ストリームで順に処理
|
556
|
+
# Pandasのデータフレームに変換(ゼロコピー!)
|
557
|
+
df = record_batch.to_pandas()
|
558
|
+
# 疎な行列に変換
|
559
|
+
corpus = csr_matrix((df["score"].values,
|
560
|
+
df["term_id"].values,
|
561
|
+
[0, df["term_id"].size]),
|
562
|
+
shape=(1, n_features))
|
563
|
+
model.partial_fit(corpus) # 学習
|
564
|
+
|
565
|
+
= トピックを確認
|
566
|
+
|
567
|
+
# coderay python
|
568
|
+
|
569
|
+
for topic in model.components_:
|
570
|
+
n_top_terms = 10
|
571
|
+
# このトピックに関連している
|
572
|
+
# 上位10単語を計算
|
573
|
+
top_term_indexes = # ↓[::-1]でreverse
|
574
|
+
topic.argsort()[:-n_top_terms-1:-1]
|
575
|
+
for i in top_term_indexes:
|
576
|
+
term_id = i # 単語ID
|
577
|
+
score = topic[i] # 関連度
|
578
|
+
print("%s:%s" % (term_id, score))
|
579
|
+
|
580
|
+
= 単語IDじゃわからん!
|
581
|
+
|
582
|
+
* 単語はIDにして計算した
|
583
|
+
* けど、確認は単語でしたい!
|
584
|
+
* 単語とIDの管理は…Rroonga!
|
585
|
+
* トピックをRubyに持っていかないと
|
586
|
+
* (('wait'))そうだ!Apache Arrowだ!
|
587
|
+
|
588
|
+
= Arrowでつながる世界
|
589
|
+
|
590
|
+
# image
|
591
|
+
# src = images/system-with-ruby.png
|
592
|
+
# relative_width = 100
|
593
|
+
|
594
|
+
(('note:(Apache License 2.0)'))
|
595
|
+
|
596
|
+
= Pythonで書き出し
|
597
|
+
|
598
|
+
# coderay python
|
599
|
+
|
600
|
+
with open("/tmp/topics", "wb") as sink:
|
601
|
+
# schema:batch.schemaで取得できる(省略)
|
602
|
+
writer = A.ipc.StreamWriter(sink, schema)
|
603
|
+
def topic_to_df(topic):
|
604
|
+
# 前述のトピックを確認した処理と同じ
|
605
|
+
values = [[i, topic[i]]
|
606
|
+
for i in topic.argsort()[:-10-1:-1]]
|
607
|
+
return pd.DataFrame(values,
|
608
|
+
columns=["term_id", "score"])
|
609
|
+
for topic in model.components_:
|
610
|
+
df = topic_to_df(topic)
|
611
|
+
batch = A.RecordBatch.from_pandas(df)
|
612
|
+
writer.write_batch(batch)
|
613
|
+
writer.close()
|
614
|
+
|
615
|
+
= Rubyで読み込み
|
616
|
+
|
617
|
+
# coderay ruby
|
618
|
+
|
619
|
+
MMF = Arrow::IO::MemoryMappedFile # 長いから
|
620
|
+
SR = Arrow::IPC::StreamReader # 長いから
|
621
|
+
MMF.open("/tmp/topics", :read) do |input|
|
622
|
+
SR.open(input) do |reader|
|
623
|
+
reader.each do |record_batch|
|
624
|
+
record_batch.each do |record|
|
625
|
+
# 単語IDを単語に変換
|
626
|
+
term = index.table[record["term_id"]]
|
627
|
+
p [term, record["score"]]
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
= 実際の結果
|
634
|
+
|
635
|
+
1: uzqpuaglzig, あきらめ, ご覧
|
636
|
+
2: useloopback, タスク
|
637
|
+
3: プラットホーム, mydog
|
638
|
+
4: delegateclass, barbar
|
639
|
+
...
|
640
|
+
|
641
|
+
(('tag:center'))
|
642
|
+
(('wait'))微妙…
|
643
|
+
|
644
|
+
= 大事なこと
|
645
|
+
|
646
|
+
Garbage in,\n
|
647
|
+
Garbage out
|
648
|
+
|
649
|
+
= 前処理をがんばる
|
650
|
+
|
651
|
+
* いらない文書を無視
|
652
|
+
* いらないトークンを無視
|
653
|
+
|
654
|
+
= いらない文書を無視
|
655
|
+
|
656
|
+
# coderay ruby
|
657
|
+
|
658
|
+
entries = Groonga["Entries"]
|
659
|
+
# 全文検索エンジンで検索するので高速!すごい!
|
660
|
+
target_entries = entries.select do |record|
|
661
|
+
(record.version == "2.4.0") -
|
662
|
+
(record.document =~ "@todo")
|
663
|
+
# ↑@todoな文書を対象外
|
664
|
+
end
|
665
|
+
# ... do |posting|
|
666
|
+
# 存在チェックも全文検索エンジンがやるので高速!
|
667
|
+
next if target_entries.key?(posting.record_id)
|
668
|
+
# ... end
|
669
|
+
|
670
|
+
= いらないトークンを無視
|
671
|
+
|
672
|
+
# coderay ruby
|
673
|
+
|
674
|
+
n_entries = target_entries.size
|
675
|
+
# ほとんどの文書に含まれるなら重要じゃない
|
676
|
+
too_many_threshold = n_entries * 0.9
|
677
|
+
# ごく一部の文書にしか含まれないなら重要じゃない
|
678
|
+
too_less_threshold = n_entries * 0.01
|
679
|
+
# ... do |term|
|
680
|
+
n_match_documents = index.estimate_size(term)
|
681
|
+
next if n_match_documents >= too_much_threshold
|
682
|
+
next if n_match_documents <= too_less_threshold
|
683
|
+
# ... end
|
684
|
+
|
685
|
+
= 実際の結果
|
686
|
+
|
687
|
+
1: self, ブロック
|
688
|
+
2: each, enumerator
|
689
|
+
3: integer, 整数, 表示
|
690
|
+
4: ruby, object
|
691
|
+
...
|
692
|
+
|
693
|
+
(('tag:center'))
|
694
|
+
(('wait'))それっぽくなってきた!
|
695
|
+
|
696
|
+
= まとめ(1)
|
697
|
+
|
698
|
+
* Rubyでデータ分析
|
699
|
+
* 全部はムリ
|
700
|
+
* でも一部ならいける
|
701
|
+
|
702
|
+
= まとめ(2)
|
703
|
+
|
704
|
+
* 一部ならいけるのは…
|
705
|
+
* Apache Arrowの登場\n
|
706
|
+
データ交換しやすくなる
|
707
|
+
* Rroongaの存在\n
|
708
|
+
Rubyで高速に自然言語処理できる
|
709
|
+
|
710
|
+
= まとめ(3)
|
711
|
+
|
712
|
+
* RubyでApache Arrow
|
713
|
+
* バインディングが必要
|
714
|
+
* GObject Introspection\n
|
715
|
+
ベースで作った(arrow-glib)
|
716
|
+
|
717
|
+
= まとめ(4)
|
718
|
+
|
719
|
+
* GObject Introspection
|
720
|
+
* だいたいいい感じ
|
721
|
+
* さらに一手間でグッとよくなる
|
722
|
+
|
723
|
+
= まとめ(5)
|
724
|
+
|
725
|
+
* 実際に分析してみた
|
726
|
+
* Rubyで前処理\n
|
727
|
+
↓Arrow
|
728
|
+
* Pythonで分析\n
|
729
|
+
↓Arrow
|
730
|
+
* Rubyで確認\n
|
731
|
+
(('note:(本当は全文検索用DBに入れて活用する)'))
|
732
|
+
|
733
|
+
= まとめ(6)
|
734
|
+
|
735
|
+
* Rubyでデータ分析いけそう!
|
736
|
+
* Arrowでデータの受け渡しが容易に\n
|
737
|
+
→分析処理へのRubyの参加が容易に
|
738
|
+
* RroongaでRubyでも高速に\n
|
739
|
+
自然言語処理をできる
|
740
|
+
|
741
|
+
= おしらせ(1)
|
742
|
+
|
743
|
+
* Rubyでデータ分析したい人は\n
|
744
|
+
クリアコードに相談してね!
|
745
|
+
* 道具の用意・活用を手伝える
|
746
|
+
|
747
|
+
# image
|
748
|
+
# src = images/clear-code.svg
|
749
|
+
# relative_width = 100
|
750
|
+
|
751
|
+
= おしらせ(2)
|
752
|
+
|
753
|
+
* Groonga Meatup名古屋2017
|
754
|
+
* 時間:明日の午前(10:00-)
|
755
|
+
* 場所:Misoca
|
756
|
+
|
757
|
+
# image
|
758
|
+
# src = images/groonga-logo.svg
|
759
|
+
# relative_height = 100
|
760
|
+
|
761
|
+
= 別案
|
762
|
+
|
763
|
+
* RroongaのPython版を作る
|
764
|
+
* RubyもArrowも必要なくなる…
|
765
|
+
* けど、より高速に前処理できる!
|
766
|
+
* (('wait'))Cythonで作ろうかと思っている…
|