rabbit-slide-kou-okinawa-rubykaigi-02 2018.3.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e1daa592cd5f2eae875752190067c783883a382d
4
+ data.tar.gz: 3543d9415d62ebfe9c90b1d1c02a453ad11912c8
5
+ SHA512:
6
+ metadata.gz: 15e71378ff100e5f20d8f235e021813d648eb143027a31235526c64615e887f75f64cb834b6b587569155fb34fc52d0441b28922197bd9f0834a9d662631af0d
7
+ data.tar.gz: c79103e61a0c9476e90686a929d6c97ef426b1a849f743757a6eb42b5ef36caba8b3d0e03e12e31c39f2866a7a1c3e220b9fc42a0f300f3fc2110687a0b109c8
data/.rabbit ADDED
@@ -0,0 +1 @@
1
+ red-data-tools.rab
data/README.rd ADDED
@@ -0,0 +1,44 @@
1
+ = Red Data Tools
2
+
3
+ Rubyでデータ処理するツールが足りないなら自分たちで楽しく作ればいいじゃんねー。よーし、作るかー!というプロジェクトがRed Data Toolsです。そんなRed Data Toolsプロジェクトが作っているツールの実装を紹介します。楽しそうだなー、一緒に作りたいなー、と思ったなら私の勝ちです。
4
+
5
+ == ライセンス
6
+
7
+ === スライド
8
+
9
+ CC BY-SA 4.0
10
+
11
+ 原著作者名は以下の通りです。
12
+
13
+ * 須藤功平(またはKouhei Sutou)
14
+
15
+ === 画像
16
+
17
+ ==== 各種クリアコード関連のロゴ
18
+
19
+ CC BY-SA 4.0
20
+
21
+ 原著作者名は以下の通りです。
22
+
23
+ * 株式会社クリアコード
24
+
25
+ == 作者向け
26
+
27
+ === 表示
28
+
29
+ rake
30
+
31
+ === 公開
32
+
33
+ rake publish
34
+
35
+ == 閲覧者向け
36
+
37
+ === インストール
38
+
39
+ gem install rabbit-slide-kou-okinawa-rubykaigi-02
40
+
41
+ === 表示
42
+
43
+ rabbit rabbit-slide-kou-okinawa-rubykaigi-02.gem
44
+
data/Rakefile ADDED
@@ -0,0 +1,17 @@
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("*.rb")
9
+ # spec.files -= Dir.glob("private/**/*.*")
10
+ spec.add_runtime_dependency("rabbit-theme-clear-code")
11
+ end
12
+
13
+ desc "Tag #{spec.version}"
14
+ task :tag do
15
+ sh("git", "tag", "-a", spec.version.to_s, "-m", "Publish #{spec.version}")
16
+ sh("git", "push", "--tags")
17
+ end
data/config.yaml ADDED
@@ -0,0 +1,25 @@
1
+ ---
2
+ id: okinawa-rubykaigi-02
3
+ base_name: red-data-tools
4
+ tags:
5
+ - rabbit
6
+ - okrk02
7
+ - red-data-tools
8
+ presentation_date: 2018-03-10
9
+ presentation_start_time:
10
+ presentation_end_time:
11
+ version: 2018.3.10.0
12
+ licenses:
13
+ - CC BY-SA 4.0
14
+ slideshare_id:
15
+ speaker_deck_id:
16
+ ustream_id:
17
+ vimeo_id:
18
+ youtube_id:
19
+ author:
20
+ markup_language: :rd
21
+ name: 須藤功平
22
+ email: kou@clear-code.com
23
+ rubygems_user: kou
24
+ slideshare_user: kou
25
+ speaker_deck_user:
Binary file
data/lavie.png ADDED
Binary file
data/no-alpha.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "arrow-gdk-pixbuf"
4
+ require "arrow-numo-narray"
5
+
6
+ pixbuf = GdkPixbuf::Pixbuf.new(file: "lavie.png")
7
+
8
+ narray = pixbuf.to_arrow.to_narray
9
+ narray[true, true, 3] = 0xff
10
+ no_alpha_pixbuf = narray.to_arrow.to_pixbuf
11
+
12
+ no_alpha_pixbuf.save("png", filename: "lavie-no-alpha.png")
13
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ n = 40
4
+ 1.upto(n) do |i|
5
+ stat = File.read("/proc/self/stat").sub(/\A.+\) /, "").split
6
+ process_group_id = stat[2]
7
+ terminal_process_group_id = stat[5]
8
+ if process_group_id == terminal_process_group_id
9
+ print("\r|%-*s|" % [n, "*" * i])
10
+ end
11
+ sleep(0.1)
12
+ end
13
+ puts
14
+ puts("Done")
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "io/console/size"
4
+
5
+ n = 40
6
+ 1.upto(n) do |i|
7
+ height, width = IO.console_size
8
+ progress_width = width - "||".size
9
+ if progress_width > 0
10
+ ratio = (progress_width * (i / n.to_f)).ceil
11
+ print("\r|%-*s|" % [progress_width, "*" * ratio])
12
+ end
13
+ sleep(0.1)
14
+ end
15
+ puts
data/progress.rb ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ n = 40
4
+ 1.upto(n) do |i|
5
+ print("\r|%-*s|" % [n, "*" * i])
6
+ sleep(0.05)
7
+ end
8
+ puts
data/read-csv.rb ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "arrow"
4
+ require "parquet"
5
+
6
+ table = Arrow::Table.load("sample.csv")
7
+ table.save("sample.arrow")
8
+ table.save("sample.parquet")
9
+
10
+ puts(Arrow::Table.load("sample.parquet"))
@@ -0,0 +1,1006 @@
1
+ = Red Data Tools
2
+
3
+ : subtitle
4
+ 楽しく実装すればいいじゃんねー
5
+ : author
6
+ 須藤功平
7
+ : institution
8
+ 株式会社クリアコード
9
+ : content-source
10
+ 沖縄Ruby会議02
11
+ : date
12
+ 2018-03-10
13
+ : start-time
14
+ 2018-03-10T13:00:00+09:00
15
+ : end-time
16
+ 2018-03-10T13:50:00+09:00
17
+ : theme
18
+ clear-code
19
+
20
+ = Red Data Tools
21
+
22
+ プロジェクト
23
+
24
+ = 実現したいこと
25
+
26
+ Rubyで\n
27
+ データ処理
28
+
29
+ = やっていること
30
+
31
+ データ処理用の\n
32
+ ツールの開発
33
+
34
+ = 開発例
35
+
36
+ * 各種フォーマットを扱うgem
37
+ * Apache Arrow, Apache Parquet, CSV, ...
38
+ * 各種パッケージの用意
39
+ * deb, RPM, Homebrew, ...
40
+ * ...
41
+
42
+ = この話の目的
43
+
44
+ 勧誘\n
45
+ (('note:一緒に開発しようぜ!'))
46
+
47
+ = 勧誘方法
48
+
49
+ * プロジェクトのポリシーを紹介
50
+ * 一緒に活動したくなる!
51
+ * 開発の具体例を紹介
52
+ * 一緒に開発したくなる!
53
+
54
+ = ポリシー1
55
+
56
+ (('tag:center'))
57
+ (('tag:large'))
58
+ Rubyコミュニティーを\n
59
+ 超えて協力する\n
60
+ (('note:もちろんRubyコミュニティーとも協力する'))
61
+
62
+ == スライドプロパティー
63
+
64
+ : as-large-as-possible
65
+ false
66
+
67
+ = Rubyに閉じずに協力
68
+
69
+ * 他の言語は敵ではない
70
+ * 他の言語がよくなることは\n
71
+ Rubyがなにかを失うことではない
72
+ * みんなよくなったらいいじゃん
73
+ * Rubyも他の言語も
74
+
75
+ = 協力例\n(('note:Apache Arrow'))
76
+
77
+ * Pythonの人達他と一緒にC/C++のライブラリーを開発
78
+ * それぞれでバインディングを開発
79
+ * それぞれで同じライブラリーを活用
80
+
81
+ = ポリシー2
82
+
83
+ (('tag:center'))
84
+ (('tag:large'))
85
+ 非難することよりも\n
86
+ 手を動かすことが大事
87
+
88
+ == スライドプロパティー
89
+
90
+ : as-large-as-possible
91
+ false
92
+
93
+ = 非難しない
94
+
95
+ そんなことを\n
96
+ している\n
97
+ 時間はない
98
+
99
+ = 手を動かす
100
+
101
+ * これ、よくないなー
102
+ * よくすればいいじゃんねー
103
+ * これがないからなー
104
+ * 作ればいいじゃんねー
105
+
106
+ = ポリシー3
107
+
108
+ (('tag:center'))
109
+ (('tag:large'))
110
+ 一回だけの活発な活動より\n
111
+ 小さくても\n
112
+ 継続的に活動することが\n
113
+ 大事
114
+
115
+ == スライドプロパティー
116
+
117
+ : as-large-as-possible
118
+ false
119
+
120
+ = 一回だけの活発な活動
121
+
122
+ * ○○作ったよ!どーん!
123
+ * すごい!
124
+ * (('note:…数年後…'))今動かないんだよね…
125
+
126
+ = 継続的な活動
127
+
128
+ * ちまちま○○作ってるんだー!
129
+ * がんばってね!今後に期待!
130
+ * (('note:…数年後…'))これは…使える!
131
+
132
+ = 継続的な活動のために
133
+
134
+ * がんばり過ぎない
135
+ * 短距離走ではなくマラソン
136
+ * 途中で休んだっていい
137
+ * 1人で抱え込まない
138
+ * みんなでやれば途中で休みやすい
139
+
140
+ = ポリシー4
141
+
142
+ (('tag:center'))
143
+ (('tag:large'))
144
+ 現時点での知識不足は\n
145
+ 問題ではない
146
+
147
+ == スライドプロパティー
148
+
149
+ : as-large-as-possible
150
+ false
151
+
152
+ = 知識不足?
153
+
154
+ * 高速な実装の実現
155
+ * プログラミング・数学などの\n
156
+ 高度な知識は便利
157
+ * 今すごい人でも\n
158
+ 最初はなにも知らなかった
159
+ * 「今知らないこと」は\n
160
+ 「始めない理由」にはならない
161
+
162
+ = 私たちは学べる
163
+
164
+ * 知識は身につく
165
+ * 活動していく中で自然と
166
+ * 学び方
167
+ * OSSの既存実装から学習
168
+ * ドキュメントを読む
169
+ * 他の人から教えてもらう
170
+
171
+ = ポリシー5
172
+
173
+ (('tag:center'))
174
+ (('tag:large'))
175
+ 部外者からの非難は\n
176
+ 気にしない
177
+
178
+ == スライドプロパティー
179
+
180
+ : as-large-as-possible
181
+ false
182
+
183
+ = 部外者からの非難
184
+
185
+ * Rubyで頑張ってもアレだよねー\n
186
+ とか
187
+ * 無視する
188
+ * 対応している時間はない
189
+
190
+ = ポリシー6
191
+
192
+ 楽しくやろう!
193
+
194
+ = 楽しむ
195
+
196
+ 使っているのは\n
197
+ Rubyだから!
198
+
199
+ = ポリシー
200
+
201
+ * Ruby外とも協力
202
+ * 非難するより手を動かす
203
+ * 継続的な活動
204
+ * 知識不足は問題ない
205
+ * 外からの非難は気にしない
206
+ * 楽しくやろう!
207
+
208
+ = 開発例
209
+
210
+ * ツールの紹介((*ではない*))
211
+ * 実装の紹介
212
+ * 開発中に((*おっ*))と思ったやつとか
213
+ * 紹介したいやつとか
214
+
215
+ = 開発例1
216
+
217
+ csv
218
+
219
+ = csv
220
+
221
+ * CSVの読み書きライブラリー
222
+ * 2003年から標準添付
223
+ * 2018年からメンテナンスを引取
224
+
225
+ = (({dig}))を追加したとき
226
+
227
+ (('tag:x-small'))((<URL:https://github.com/ruby/csv/pull/15>))
228
+
229
+ * (({CSV::Table#dig}))
230
+ * (({CSV::Row#dig}))
231
+
232
+ = (({dig}))の作り方
233
+
234
+ # rouge ruby
235
+
236
+ def dig(index, *indexes)
237
+ # ここだけ違う
238
+ value = find_value(index)
239
+ # ↓は共通
240
+ return nil if value.nil?
241
+ return value if indexes.empty?
242
+ value.dig(*indexes)
243
+ end
244
+
245
+ = (({CSV::Row}))での(({find_value}))
246
+
247
+ # rouge ruby
248
+
249
+ row[index] # => field value
250
+
251
+ (({dig}))の中では(({self}))の(({[]}))を呼べばよい
252
+
253
+ = (({[]}))の呼び方
254
+
255
+ # rouge ruby
256
+
257
+ def dig(index, *indexes)
258
+ # インスタンスメソッドでは
259
+ # selfを省略できるからこう?
260
+ value = [index]
261
+ # ↑は配列リテラル
262
+ # ...
263
+ end
264
+
265
+ = (({[]}))の呼び方
266
+
267
+ # rouge ruby
268
+
269
+ def dig(index, *indexes)
270
+ # こういうときこそsendで  
271
+ # メソッド呼び出し
272
+ value = send(:[], index)
273
+ # 動く
274
+ # ...
275
+ end
276
+
277
+ = (({[]}))の呼び方
278
+
279
+ # rouge ruby
280
+
281
+ def dig(index, *indexes)
282
+ # row[index]みたいに書けば 
283
+ # よかった
284
+ value = self[index]
285
+ # もちろん動く
286
+ # ...
287
+ end
288
+
289
+ = (({self}))の(({[]}))の呼び方
290
+
291
+ * 自分も昔悩んだ気がする
292
+ * 懐かしかったので紹介
293
+ * みんなで開発🠊気づきやすい
294
+
295
+ = 開発例2
296
+
297
+ Red Datasets
298
+
299
+ = Red Datasets
300
+
301
+ * データを簡単に使えるように!
302
+ * 実験・開発に便利
303
+
304
+ = 例:日本語データ欲しい!
305
+
306
+ # rouge ruby
307
+ require "datasets"
308
+ # 日本語版Wikipediaの記事データ
309
+ options = {language: :ja, type: :articles}
310
+ dataset = Datasets::Wikipedia.new(options)
311
+ dataset.each do |page| # 全ページを順に処理
312
+ p page.title # タイトル
313
+ p page.revision.text # 本文
314
+ end
315
+
316
+ (('tag:center'))
317
+ (('note:インターフェイスがeachなのがカッコいいんだよ!'))
318
+
319
+ = 実装方法
320
+
321
+ (1) データのダウンロード
322
+ (2) データのパース
323
+ (3) 順に(({yield}))
324
+
325
+ = ダウンロード
326
+
327
+ # rouge ruby
328
+ require "open-uri"
329
+ open("https://...") do |input|
330
+ File.open("...", "wb") do |output|
331
+ IO.copy_stream(input, output)
332
+ end
333
+ end
334
+
335
+ = 途中でエラーになったら?
336
+
337
+ (('tag:center'))
338
+ (('tag:x-large'))
339
+ やり直し
340
+
341
+ (('tag:center'))
342
+ または
343
+
344
+ (('tag:center'))
345
+ (('tag:x-large'))
346
+ 再開
347
+
348
+ = 再開
349
+
350
+ HTTP\n
351
+ range request
352
+
353
+ = HTTP range request
354
+
355
+ * リクエスト
356
+ * (({Range: bytes=#{start}-}))
357
+ * レスポンス
358
+ * (({206 Partial Content}))
359
+ * (({Content-Range: bytes ...}))
360
+
361
+ = open-uriとrange request
362
+
363
+ * open-uriはrange request未対応
364
+ * 出力無関係のAPIだからしょうがない
365
+ * どうなるのがいいだろう?
366
+ * 今度田中さんに相談しよう
367
+ * Red Data ToolsはRubyもよくしたい\n
368
+ (('note:ポリシー1:コミュニティーを超えて協力'))
369
+
370
+ = open-uriでrange request
371
+
372
+ # rouge ruby
373
+ # 文字列キーはHTTPヘッダーになる
374
+ options = {"Range" => "bytes=#{start}-"}
375
+ open("...", options) do |input|
376
+ # レスポンスが200か206かはわからない
377
+ File.open("...", "ab") do |output|
378
+ IO.copy_stream(input, output)
379
+ end
380
+ end
381
+
382
+ = 大きなデータの扱い
383
+
384
+ * 時間がかかる
385
+ * あとどのくらいか気になる
386
+ * ちゃんと動いているよね…?
387
+
388
+ = あとどのくらい?
389
+
390
+ プログレスバー
391
+
392
+ = プログレスバーの実装
393
+
394
+ # rouge ruby
395
+
396
+ n = 40
397
+ 1.upto(n) do |i|
398
+ print("\r|%-*s|" % [n, "*" * i])
399
+ sleep(0.1)
400
+ end
401
+ puts
402
+
403
+ = sprintfフォーマット
404
+
405
+ (('tag:center'))
406
+ (({%-*s}))
407
+
408
+ * (({%})):フォーマット開始
409
+ * (({-})):左詰め
410
+ * (({*})):引数で幅を指定
411
+ * (({s})):対象は文字列
412
+
413
+ = sprintfフォーマット
414
+
415
+ (('tag:center'))
416
+ (({"%-*s" % [n, "*" * i]}))
417
+
418
+ * 幅は(({n}))桁
419
+ * (({"*" * i}))を左詰め
420
+
421
+ = open-uriでプログレスバー
422
+
423
+ # rouge ruby
424
+
425
+ length = nil
426
+ progress = lambda do |current|
427
+ ratio = current / length.to_f
428
+ print("\r|%-10s|" % ["*" * (ratio * 10).ceil])
429
+ end
430
+ open(uri,
431
+ content_length_proc: ->(l) {length = l},
432
+ progress_proc: progress) do |input|
433
+ # ...
434
+ end
435
+ puts
436
+
437
+ = もっとプログレスバー
438
+
439
+ * バックグランド化したら?
440
+ * 表示して欲しくない\n
441
+ (('note:ヒント:プロセスグループ'))
442
+ * リダイレクトしているときは?
443
+ * 表示して欲しくない\n
444
+ (('note:ヒント:IO#tty?'))
445
+ * プログレスバーの表示幅は?\n
446
+ (('note:ヒント:io/console/size'))
447
+
448
+ = 開発例3
449
+
450
+ Apache Arrow\n
451
+ Red Arrow
452
+
453
+ = Apache Arrow
454
+
455
+ * インメモリーデータ分析用\n
456
+ データフォーマット\n
457
+ (('note:ほぼ固まってきた'))
458
+ * インメモリーデータ分析用\n
459
+ 高速なデータ操作実装\n
460
+ (('note:徐々に実装が始まっている'))
461
+ * 今、すごくアツい!
462
+
463
+ = Apache Arrowの特徴
464
+
465
+ (('tag:center'))
466
+ (('tag:large'))
467
+ データ交換コストが低い
468
+
469
+ == スライドプロパティー
470
+
471
+ : as-large-as-possible
472
+ false
473
+
474
+ = 低データ交換コスト
475
+
476
+ * 複数システムで協力しやすい
477
+ * Rubyでデータ取得🠊Pythonで分析
478
+ * 徐々にRubyを使えるところを\n
479
+ 増やせる
480
+
481
+ = Apache Arrowの利用例
482
+
483
+ * Scala🤝Python
484
+ * (('tag:x-small'))Apache Spark
485
+ * CPU🤝GPU
486
+ * (('tag:x-small'))((<URL:https://github.com/gpuopenanalytics/libgdf>))
487
+ * CPU🤝FPGA
488
+ * (('tag:x-small'))((<URL:https://github.com/johanpel/fletcher>))
489
+
490
+ = Apache ArrowをRubyでも!
491
+
492
+ * バインディングを本体で開発
493
+ * 本体の開発チームに入った\n
494
+ * GObject Introspection(GI)を利用
495
+ * GIを使うとRuby以外のバインディングも自動生成できる\n
496
+ (('note:ポリシー1:コミュニティーを超えて協力'))
497
+
498
+ = Red Arrow
499
+
500
+ * Apache Arrowの\n
501
+ Rubyバインディング
502
+ * GIベースのバインディングに\n
503
+ Ruby特有の機能をプラス
504
+
505
+ = Ruby特有の機能例
506
+
507
+ スライスAPI
508
+
509
+ = スライス
510
+
511
+ (('tag:center'))
512
+ データの一部を切り出す
513
+
514
+ # rouge ruby
515
+
516
+ (0..10).to_a.slice(2)
517
+ # => 2
518
+ (0..10).to_a.slice(2..4)
519
+ # => [2, 3, 4]
520
+ (0..10).to_a.slice(2, 4)
521
+ # => [2, 3, 4, 5]
522
+
523
+ = Red Arrowのスライス
524
+
525
+ # rouge ruby
526
+
527
+ table.slice(2)
528
+ # 2行目だけのテーブル
529
+ # Array#sliceと違う
530
+
531
+ = Red Arrowのスライス
532
+
533
+ # rouge ruby
534
+
535
+ table.slice(2..4)
536
+ # 2,3,4行目だけのテーブル
537
+ # Array#sliceと同じ
538
+
539
+ = Red Arrowのスライス
540
+
541
+ # rouge ruby
542
+
543
+ table.slice(2, 4)
544
+ # 2,4行目だけのテーブル
545
+ # Array#sliceと違う
546
+ table.slice(2, 4, 6, 8)
547
+ # 2,4,6,8行目だけのテーブル
548
+ # Array#sliceと違う
549
+
550
+ = Red Arrowのスライス
551
+
552
+ # rouge ruby
553
+
554
+ table.slice([2, 4])
555
+ # 2,3,4,5行目だけのテーブル
556
+ # Array#slice(2, 4)と同じ
557
+
558
+ = Red Arrowのスライス
559
+
560
+ # rouge ruby
561
+
562
+ table.slice([true, false] * 5)
563
+ # 0,2,4,6,8行目だけのテーブル
564
+
565
+ = Red Arrowのスライス
566
+
567
+ # rouge ruby
568
+
569
+ table.slice do |slicer|
570
+ slicer.price >= 500
571
+ end
572
+ # priceカラムの値が500以上の
573
+ # 行だけのテーブル
574
+
575
+ = Red Arrowのスライス
576
+
577
+ # rouge ruby
578
+
579
+ table.slice do |slicer|
580
+ (slicer.price >= 500) &
581
+ (slicer.is_published)
582
+ end
583
+ # priceカラムの値が500以上かつ
584
+ # is_publishedカラムの値がtrueの
585
+ # 行だけのテーブル
586
+
587
+ = Red Arrowのスライス
588
+
589
+ Active Recordみたいなfluent intefaceよりもブロック内で式を書く方がRubyっぽいんじゃないかと思うんだよねー\n
590
+ fluent interfaceはORを書きにくいからさー
591
+
592
+ (('tag:xx-small'))
593
+ Fluent interface:\n
594
+ ((<URL:http://bliki-ja.github.io/FluentInterface/>))
595
+
596
+ = ブロック内で条件式
597
+
598
+ # rouge ruby
599
+
600
+ class Arrow::Table
601
+ # table.slice {|slicer| ...}の実現
602
+ def slice(*slicers)
603
+ if block_given?
604
+ slicer = yield(Slicer.new(self))
605
+ slicers << slicer.evaluate
606
+ end
607
+ # ...
608
+ end
609
+ end
610
+
611
+ = ブロック内で条件式
612
+
613
+ # rouge ruby
614
+
615
+ class Arrow::Slicer
616
+ def initialize(table)
617
+ @table = table
618
+ end
619
+
620
+ # slicer.priceの実現
621
+ def method_missing(name, *args, &block)
622
+ ColumnCondition.new(@table[name])
623
+ end
624
+ end
625
+
626
+ = ブロック内で条件式
627
+
628
+ # rouge ruby
629
+
630
+ class ColumnCondition < Condition
631
+ def initialize(column)
632
+ @column = column
633
+ end
634
+
635
+ # slicer.price >= 500の実現
636
+ def >=(value)
637
+ GreaterEqualCondition.new(@column, value)
638
+ end
639
+ end
640
+
641
+ = ブロック内で条件式
642
+
643
+ # rouge ruby
644
+
645
+ class GreaterEqualCondition < Condition
646
+ def initialize(column, value)
647
+ @column = column
648
+ @value = value
649
+ end
650
+
651
+ # slicer.price >= 500を評価
652
+ def evaluate
653
+ # ホントはC++で実装
654
+ @column.collect {|value| value >= @value}
655
+ end
656
+ end
657
+
658
+ = ブロック内で条件式
659
+
660
+ # rouge ruby
661
+
662
+ class Condition
663
+ # (slicer.price >= 500) & (...)の実現
664
+ def &(condition)
665
+ AndCondition.new(self, condition)
666
+ end
667
+ end
668
+
669
+ = 条件式のポイント
670
+
671
+ * 遅延評価
672
+ * ❌各要素毎にブロックを評価
673
+ * ブロックは一回だけ評価
674
+ * ブロックで指定した条件は\n
675
+ コンパイルしてC++実装で実行
676
+
677
+ = Red Arrowと外の世界
678
+
679
+ * ハブになるといいかも!
680
+ * 各種データと変換可能に
681
+ * 各種オブジェクトと変換可能に
682
+ * Ruby間の連携を推進
683
+ * 今は互換性がないライブラリー\n
684
+ 🠊連携できるように!
685
+
686
+ = データ変換
687
+
688
+ * (({Arrow::Table.load}))
689
+ * データの読み込み
690
+ * (({Arrow::Table#save}))
691
+ * データの書き出し
692
+
693
+ = データ変換例
694
+
695
+ # rouge ruby
696
+
697
+ # CSVを読み込んで
698
+ table = Arrow::Table.load("a.csv")
699
+ # Arrowで保存
700
+ table.save("a.arrow")
701
+ # Parquetで保存
702
+ table.save("a.parquet")
703
+
704
+ = CSVの読み込み
705
+
706
+ * CSVは広く使われている
707
+ * CSVなデータを簡単に使えると捗る
708
+ * 難しいところ
709
+ * データ定義が緩い\n
710
+ 例:カラムの型情報がない
711
+
712
+ = Red Arrowでの読み込み
713
+
714
+ * 2パスで処理
715
+ (1) 全部処理して各カラムの型を推定
716
+ (2) 推定した型でArrowのデータに変換
717
+ * 😅時間がかかる
718
+ * 読み込んだデータを別の形式に変換して再利用する使い方を想定\n
719
+ だから、まぁ、いいかなぁって
720
+
721
+ = 型の推定
722
+
723
+ # rouge ruby
724
+
725
+ candidate = nil
726
+ column.each do |value|
727
+ case value
728
+ when nil; next # ignore
729
+ when "true", "false", true, false; c = :boolean
730
+ when Integer; c = :integer
731
+ # ...
732
+ else; c = :string # わからなかったら文字列
733
+ end
734
+ candidate ||= c
735
+ candidate = :string if candidate != c # 混ざったら文字列
736
+ break if candidate == :string # 文字列なら終わり
737
+ end
738
+ candidate || :string # わからなかったら文字列
739
+
740
+ = オブジェクト変換
741
+
742
+ * Numo::NArray, NMatrix
743
+ * 既存の多次元配列オブジェクト
744
+ * PyCall経由でPyArrow
745
+ * Rubyでデータ作成🠊Pythonで処理
746
+ * GDK Pixbuf
747
+ * 画像オブジェクト
748
+
749
+ = オブジェクト変換例
750
+
751
+ # rouge ruby
752
+
753
+ # PNG画像を読み込み
754
+ pixbuf = GdkPixbuf::Pixbuf.new(file: "a.png")
755
+ # Arrow経由でNumo::NArrayに変換
756
+ narray = pixbuf.to_arrow.to_narray
757
+ # 不透明に(アルファ値(透明度)を0xffに)
758
+ narray[true, true, 3] = 0xff
759
+ # Arrow経由でGdkPixbuf::Pixbufに変換
760
+ no_alpha_pixbuf = narray.to_arrow.to_pixbuf
761
+ # GIF画像として保存
762
+ no_alpha_pixbuf.save(filename: "a-no-alpha.gif")
763
+
764
+ = Pixbuf→Arrow
765
+
766
+ # rouge ruby
767
+
768
+ class GdkPixbuf::Pixbuf
769
+ def to_arrow
770
+ bytes = read_pixel_bytes # ピクセル値
771
+ buffer = Arrow::Buffer.new(bytes)
772
+ # 高さ、幅、チャンネル数の3次元配列
773
+ # チャンネル数:RGBAだと4チャンネル
774
+ shape = [height, width, n_channels]
775
+ # バイト列なのでUInt8
776
+ Arrow::Tensor.new(Arrow::UInt8DataType.new,
777
+ buffer, shape)
778
+ end
779
+ end
780
+
781
+ = ゼロコピーの実現
782
+
783
+ * ゼロコピー
784
+ * 同じメモリー領域を参照し、\n
785
+ コピーせずに同じデータを利用
786
+ * 速い!!!
787
+ * データ
788
+ * バイト列へのポインター
789
+ * Rubyでは(({RSTRING_PTR(string)}))
790
+
791
+ = (({String}))とゼロコピー
792
+
793
+ # rouge c
794
+
795
+ /* pointerの内容をコピー */
796
+ rb_str_new(pointer, size);
797
+ /* pointerの内容を参照:ゼロコピー */
798
+ rb_str_new_static(pointer, size);
799
+
800
+ = (({String}))とゼロコピーとGC
801
+
802
+ # rouge c
803
+
804
+ arrow_data = /* ... */;
805
+ /* ゼロコピー */
806
+ rb_str_new_static(arrow_data, size);
807
+ /* arrow_dataはいつ、だれが開放? */
808
+
809
+ = Rubyでゼロコピー
810
+
811
+ * ❌(({rb_str_new_static()}))だけ
812
+ * メモリー管理できない
813
+ * メモリー管理する何かが必要
814
+
815
+ = Red Arrowでゼロコピー
816
+
817
+ * GBytesを利用
818
+ * GBytes
819
+ * GLib提供のバイト列オブジェクト
820
+ * リファレンスカウントあり
821
+ * Rubyだと(({GLib::Bytes}))
822
+
823
+ = (({GLib::Bytes#to_s}))
824
+
825
+ # rouge c
826
+
827
+ static VALUE rgbytes_to_s(VALUE self) {
828
+ GBytes *bytes = RVAL2BOXED(self, G_TYPE_BYTES);
829
+ gsize size;
830
+ gconstpointer data =
831
+ g_bytes_get_data(bytes, &size);
832
+ /* ゼロコピーでASCII-8BITな文字列を生成 */
833
+ VALUE rb_data = rb_enc_str_new_static(
834
+ data, size, rb_ascii8bit_encoding());
835
+ rb_iv_set(rb_data, "@bytes", self); /* GC対策 */
836
+ return rb_data;
837
+ }
838
+
839
+ = (({GLib::Bytes#initialize}))
840
+
841
+ # rouge c
842
+
843
+ static VALUE rgbytes_initialize(VALUE self, VALUE rb_data) {
844
+ const char *pointer = RSTRING_PTR(rb_data);
845
+ long size = RSTRING_LEN(rb_data);
846
+ GBytes *bytes;
847
+ if (RB_OBJ_FROZEN(rb_data)) { /* ゼロコピー */
848
+ bytes = g_bytes_new_static(pointer, size);
849
+ rb_iv_set(self, "source", rb_data); /* GC対策 */
850
+ } else { /* コピー */
851
+ bytes = g_bytes_new(pointer, size);
852
+ }
853
+ G_INITIALIZE(self, bytes);
854
+ return Qnil;
855
+ }
856
+
857
+ = GBytesはすでに使っていた
858
+
859
+ # rouge ruby
860
+
861
+ class GdkPixbuf::Pixbuf
862
+ def to_arrow
863
+ # ピクセル値はGLib::Bytes
864
+ bytes = read_pixel_bytes
865
+ buffer = Arrow::Buffer.new(bytes)
866
+ shape = [height, width, n_channels]
867
+ Arrow::Tensor.new(Arrow::UInt8DataType.new,
868
+ buffer,
869
+ shape)
870
+ end
871
+ end
872
+
873
+ = Red Chainer
874
+
875
+ (('tag:large'))
876
+ ChainerのRuby移植
877
+
878
+ == スライドプロパティー
879
+
880
+ : as-large-as-possible
881
+ false
882
+
883
+ = Chainer
884
+
885
+ * 深層学習フレームワーク
886
+ * Pythonのみで実装
887
+ * 移植しやすい
888
+ * Pythonのみで実装されているから
889
+
890
+ = Red Chainerサンプル
891
+
892
+ # rouge ruby
893
+
894
+ model = Chainer::Links::Model::Classifier.new(MLP.new(args[:unit], 10))
895
+ optimizer = Chainer::Optimizers::Adam.new
896
+ optimizer.setup(model)
897
+ train, test = Chainer::Datasets::Mnist.get_mnist
898
+
899
+ train_iter = Chainer::Iterators::SerialIterator.new(train, args[:batchsize])
900
+ test_iter = Chainer::Iterators::SerialIterator.new(test, args[:batchsize], repeat: false, shuffle: false)
901
+
902
+ # ...
903
+
904
+ (('tag:center'))
905
+ 横に長い
906
+
907
+ = Chainerのサンプル
908
+
909
+ # rouge python
910
+
911
+ import chainer
912
+ import chainer.links as L
913
+
914
+ model = L.Classifier(MLP(args.unit, 10))
915
+ optimizer = chainer.optimizers.Adam()
916
+ optimizer.setup(model)
917
+ train, test = chainer.datasets.get_mnist()
918
+ train_iter = chainer.iterators.SerialIterator(train, args.batchsize)
919
+ test_iter = chainer.iterators.SerialIterator(test, args.batchsize,
920
+ repeat=False, shuffle=False)
921
+
922
+ (('tag:center'))
923
+ こっちも横に長い
924
+
925
+ = Pythonでの短く仕方
926
+
927
+ # rouge python
928
+
929
+ # 通常
930
+ import chainer
931
+ model = chainer.links.Classifier(MLP(args.unit, 10))
932
+
933
+ # Lでショートカット
934
+ import chainer.links as L
935
+ model = L.Classifier(MLP(args.unit, 10))
936
+
937
+ = Rubyでの短く仕方
938
+
939
+ # rouge ruby
940
+
941
+ # 通常
942
+ model = Chainer::Links::Model::Classifier.new(...)
943
+
944
+ # Lでショートカット
945
+ L = Chainer::Links
946
+ model = L::Model::Classifier.new(...)
947
+
948
+ = PythonとRubyの違い
949
+
950
+ * Python
951
+ * ファイル内でだけ(({L}))が有効
952
+ * ファイル単位でネームスペース
953
+ * Ruby
954
+ * グローバルに(({L}))が有効
955
+ * 微妙!
956
+
957
+ = Rubyらしく短く
958
+
959
+ # rouge ruby
960
+
961
+ # Rubyのネームスペースの仕組みはモジュール
962
+ Module.new do
963
+ L = Chainer::Links
964
+ model = L::Model::Classifier.new(...)
965
+ end
966
+
967
+ = 開発したくなった?
968
+
969
+ * 楽しそう!
970
+ * 一緒に開発しようぜ!
971
+ * やっぱRubyでデータ扱いたい!
972
+ * 一緒に開発しようぜ!
973
+ * レベルアップしたい!
974
+ * 一緒に開発しようぜ!
975
+
976
+ = レベルアップへの道
977
+
978
+ * 😅NG集をたくさん覚える
979
+ * 😀よいコードにたくさん触れる
980
+
981
+ = よいコード
982
+
983
+ (('tag:large'))
984
+ Red Data Toolsに\n
985
+ たくさんある!
986
+
987
+ == スライドプロパティー
988
+
989
+ : as-large-as-possible
990
+ false
991
+
992
+ = 一緒に開発
993
+
994
+ * 🌏どこからでもオンラインで
995
+ * GitHubとGitter(チャット)を使用
996
+ * ➕東京は月一オフラインで
997
+ * 🔍「OSS Gate Red Data Tools」
998
+
999
+ = Join Red Data Tools!
1000
+
1001
+ * Webサイト
1002
+ * (('tag:x-small'))((<URL:https://red-data-tools.github.io/ja/>))
1003
+ * Gitter(チャット)
1004
+ * (('tag:x-small'))((<URL:https://gitter.im/red-data-tools/ja>))
1005
+ * GitHub
1006
+ * (('tag:x-small'))((<URL:https://github.com/red-data-tools/>))
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rabbit-slide-kou-okinawa-rubykaigi-02
3
+ version: !ruby/object:Gem::Version
4
+ version: 2018.3.10.0
5
+ platform: ruby
6
+ authors:
7
+ - 須藤功平
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rabbit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: rabbit-theme-clear-code
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Rubyでデータ処理するツールが足りないなら自分たちで楽しく作ればいいじゃんねー。よーし、作るかー!というプロジェクトがRed Data
42
+ Toolsです。そんなRed Data Toolsプロジェクトが作っているツールの実装を紹介します。楽しそうだなー、一緒に作りたいなー、と思ったなら私の勝ちです。
43
+ email:
44
+ - kou@clear-code.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".rabbit"
50
+ - README.rd
51
+ - Rakefile
52
+ - config.yaml
53
+ - lavie-no-alpha.png
54
+ - lavie.png
55
+ - no-alpha.rb
56
+ - pdf/okinawa-rubykaigi-02-red-data-tools.pdf
57
+ - progress-background.rb
58
+ - progress-term-width.rb
59
+ - progress.rb
60
+ - read-csv.rb
61
+ - red-data-tools.rab
62
+ homepage: http://slide.rabbit-shocker.org/authors/kou/okinawa-rubykaigi-02/
63
+ licenses:
64
+ - CC BY-SA 4.0
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.5.2.2
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Red Data Tools
86
+ test_files: []