feldtruby 0.3.14 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/feldtruby/array/permutations_and_subsets.rb +11 -0
- data/lib/feldtruby/logger.rb +64 -0
- data/lib/feldtruby/minitest_extensions.rb +8 -0
- data/lib/feldtruby/statistics.rb +42 -5
- data/lib/feldtruby/version.rb +1 -1
- data/test/helper.rb +2 -1
- data/test/test_array_permutations_and_subsets.rb +43 -0
- data/test/test_html_doc_getter.rb +28 -9
- data/test/test_logger.rb +96 -0
- data/test/test_statistics.rb +13 -1
- metadata +8 -2
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module FeldtRuby
|
4
|
+
|
5
|
+
class Logger
|
6
|
+
def initialize(io = STDOUT)
|
7
|
+
|
8
|
+
@io = io
|
9
|
+
|
10
|
+
# We save a unique array of events for each type.
|
11
|
+
@events = Hash.new {|h,k| h[k] = Array.new}
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return the number of events of type _eventType_.
|
16
|
+
def num_events eventType = nil
|
17
|
+
@events[eventType].length
|
18
|
+
end
|
19
|
+
|
20
|
+
Event = Struct.new(:description, :time_stamp)
|
21
|
+
|
22
|
+
# Count an event of type _eventType_.
|
23
|
+
def log_event eventType = nil, description = ""
|
24
|
+
@events[eventType] << Event.new(description, Time.now)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return all the events, i.e. descriptions and time stamp, for a given _eventType_.
|
28
|
+
def events(eventType = nil)
|
29
|
+
@events[eventType]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return all the event descriptions for a given _eventType_.
|
33
|
+
def event_descriptions(eventType = nil)
|
34
|
+
@events[eventType].map {|e| e.description}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Log an event described by a string _str_ optionally with an event type
|
38
|
+
# _eventType_.
|
39
|
+
def log str, eventType = nil
|
40
|
+
|
41
|
+
description = log_entry_description(str, eventType)
|
42
|
+
|
43
|
+
log_event eventType, description
|
44
|
+
|
45
|
+
io_puts description
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
# Puts the given _str_ on the io stream.
|
50
|
+
def io_puts str
|
51
|
+
@io.puts str
|
52
|
+
end
|
53
|
+
|
54
|
+
# Map a string and event type to a log string.
|
55
|
+
def log_entry_description str, eventType = nil
|
56
|
+
|
57
|
+
event_tag = eventType ? "{#{eventType.to_s}}: " : ""
|
58
|
+
|
59
|
+
event_tag + str
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -20,6 +20,14 @@ module MiniTest::Assertions
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
NumTestRepetitions = 50
|
24
|
+
|
25
|
+
def repeatedly_it(message, &testcode)
|
26
|
+
NumTestRepetitions.times do |i|
|
27
|
+
it("#{i}: " + message, &testcode)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
23
31
|
module MiniTest::Expectations
|
24
32
|
infect_an_assertion :assert_similar_proportions, :must_have_similar_proportions
|
25
33
|
infect_an_assertion :assert_falsey, :must_be_falsey
|
data/lib/feldtruby/statistics.rb
CHANGED
@@ -110,8 +110,9 @@ class RCommunicator
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
# Convert a Ruby object of one of the types String, Array, Integer
|
114
|
-
# to a String that can be used in R code/scripts to
|
113
|
+
# Convert a Ruby object of one of the types String, Symbol, Array, Integer
|
114
|
+
# or Float to a String that can be used in R code/scripts to
|
115
|
+
# represent the object.
|
115
116
|
def ruby_object_to_R_string(o)
|
116
117
|
|
117
118
|
case o
|
@@ -119,6 +120,9 @@ class RCommunicator
|
|
119
120
|
when String
|
120
121
|
return o.inspect
|
121
122
|
|
123
|
+
when Symbol
|
124
|
+
return o.to_s
|
125
|
+
|
122
126
|
when Array
|
123
127
|
elems = o.map {|e| ruby_object_to_R_string(e)}.join(", ")
|
124
128
|
return "c(#{elems})"
|
@@ -164,6 +168,10 @@ module Statistics
|
|
164
168
|
res.p_value
|
165
169
|
end
|
166
170
|
|
171
|
+
def correlation(ary1, ary2)
|
172
|
+
RC.call("cor", ary1, ary2)
|
173
|
+
end
|
174
|
+
|
167
175
|
class DiffusionKDE
|
168
176
|
attr_reader :densities, :mesh
|
169
177
|
|
@@ -246,9 +254,38 @@ module FeldtRuby::Statistics::Plotting
|
|
246
254
|
|
247
255
|
end
|
248
256
|
|
249
|
-
def
|
257
|
+
def filled_contour(csvFilePath, xlabel, ylabel, title = "filled.contour")
|
258
|
+
include_library "MASS"
|
259
|
+
#include_library "ggplot2"
|
260
|
+
|
261
|
+
script = <<-EOS
|
262
|
+
data <- read.csv(#{csvFilePath.inspect})
|
263
|
+
k <- with(data, MASS::kde2d(#{xlabel}, #{ylabel}))
|
264
|
+
f <- filled.contour(k, color=topo.colors,
|
265
|
+
plot.title=title(main = _title_),
|
266
|
+
xlab=_xlabel_, ylab=_ylabel_)
|
267
|
+
f
|
268
|
+
EOS
|
269
|
+
|
270
|
+
subst_eval script, {:title => title,
|
271
|
+
:xlabel => xlabel.to_s, :ylabel => ylabel.to_s}
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
def smooth_scatter_plot(csvFilePath, xlabel, ylabel, title = "smoothscatter")
|
276
|
+
include_library "graphics"
|
277
|
+
|
278
|
+
script = <<-EOS
|
279
|
+
f <- ggplot(data, aes(#{xlabel}, #{ylabel})) +
|
280
|
+
geom_point() + geom_smooth( method="loess", se = FALSE )
|
281
|
+
EOS
|
282
|
+
|
283
|
+
plot_2dims(csvFilePath, script, xlabel.to_s, ylabel.to_s, title)
|
284
|
+
end
|
285
|
+
|
286
|
+
def hexbin_heatmap(csvFilePath, xlabel, ylabel, title = "heatmap", bins = 50)
|
250
287
|
plot_2dims(csvFilePath,
|
251
|
-
"f <- ggplot(data, aes(#{
|
288
|
+
"f <- ggplot(data, aes(#{xlabel}, #{ylabel})) + geom_hex( bins = #{bins} )",
|
252
289
|
xlabel, ylabel, title)
|
253
290
|
end
|
254
291
|
|
@@ -260,7 +297,7 @@ module FeldtRuby::Statistics::Plotting
|
|
260
297
|
f <- f + stat_smooth()
|
261
298
|
EOS
|
262
299
|
|
263
|
-
plot_2dims(csvFilePath, script, xlabel, ylabel, title)
|
300
|
+
plot_2dims(csvFilePath, script, xlabel.to_s, ylabel.to_s, title)
|
264
301
|
|
265
302
|
end
|
266
303
|
|
data/lib/feldtruby/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'feldtruby/array/permutations_and_subsets'
|
2
|
+
|
3
|
+
describe "all pairs of elements from an array" do
|
4
|
+
|
5
|
+
it "cannot return any pairs if there are fewer than 2 elements" do
|
6
|
+
|
7
|
+
[].all_pairs.must_equal []
|
8
|
+
[1].all_pairs.must_equal []
|
9
|
+
[:a].all_pairs.must_equal []
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns the only pair if 2 elements" do
|
14
|
+
|
15
|
+
[1, 2].all_pairs.must_equal [[1, 2]]
|
16
|
+
[1, "a"].all_pairs.must_equal [[1, "a"]]
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns the right pairs when 3 elements" do
|
21
|
+
|
22
|
+
[1, 2, 3].all_pairs.sort.must_equal [[1, 2], [1, 3], [2, 3]].sort
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def invariant_all_original_elements_are_at_least_in_one_pair(ary)
|
27
|
+
|
28
|
+
ary.all_pairs.flatten.uniq.sort.must_equal ary.uniq.sort
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
repeatedly_it "returns the right number of pairs when > 3 elements" do
|
33
|
+
|
34
|
+
ary = Array.new(4 + rand(10)).map {rand(1000)}
|
35
|
+
|
36
|
+
invariant_all_original_elements_are_at_least_in_one_pair ary
|
37
|
+
|
38
|
+
num_pairs = ary.all_pairs
|
39
|
+
n = ary.length
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -1,16 +1,35 @@
|
|
1
1
|
require 'minitest/spec'
|
2
2
|
require 'feldtruby/net/html_doc_getter'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
# Skip these network-dependent tests if we have no network connection.
|
5
|
+
def has_network_connection?
|
6
|
+
begin
|
7
|
+
open("http://www.google.se")
|
8
|
+
return true
|
9
|
+
rescue Exception => e
|
10
|
+
return false
|
9
11
|
end
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
def quicker_has_network_connection?
|
15
|
+
reply = `ping -o google.se`
|
16
|
+
reply != "" # Is empty if no connection since error is printed on STDERR
|
17
|
+
end
|
18
|
+
|
19
|
+
if quicker_has_network_connection?
|
20
|
+
|
21
|
+
describe "HtmlDocGetter" do
|
22
|
+
it "Can get the html page as a string" do
|
23
|
+
h = FeldtRuby::HtmlDocGetter.new
|
24
|
+
s = h.get("http://www.google.com")
|
25
|
+
s.must_be_instance_of String
|
26
|
+
end
|
27
|
+
|
28
|
+
it "Can get the html page as a Nokogiri doc" do
|
29
|
+
h = FeldtRuby::HtmlDocGetter.new
|
30
|
+
d = h.get_html_doc("http://www.google.com")
|
31
|
+
d.must_be_instance_of Nokogiri::HTML::Document
|
32
|
+
end
|
15
33
|
end
|
34
|
+
|
16
35
|
end
|
data/test/test_logger.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'feldtruby/logger'
|
2
|
+
|
3
|
+
describe 'Logger' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@sio = StringIO.new
|
7
|
+
@l = FeldtRuby::Logger.new @sio
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'has a event count of 0 when no events has been logged' do
|
11
|
+
|
12
|
+
@l.num_events.must_equal 0
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'increases default event count when default events are logged' do
|
17
|
+
|
18
|
+
@l.log "1"
|
19
|
+
@l.num_events.must_equal 1
|
20
|
+
|
21
|
+
@l.log "2"
|
22
|
+
@l.num_events.must_equal 2
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'can log default events (described in strings)' do
|
27
|
+
|
28
|
+
@l.log "event 1"
|
29
|
+
@sio.string.must_equal "event 1\n"
|
30
|
+
@l.num_events.must_equal 1
|
31
|
+
|
32
|
+
@l.log "event 2"
|
33
|
+
@sio.string.must_equal "event 1\nevent 2\n"
|
34
|
+
@l.num_events.must_equal 2
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'can log events of a given type' do
|
39
|
+
|
40
|
+
@l.log "1", :increase
|
41
|
+
@sio.string.must_equal "{increase}: 1\n"
|
42
|
+
@l.num_events.must_equal 0
|
43
|
+
@l.num_events(:increase).must_equal 1
|
44
|
+
|
45
|
+
@l.log "2", :increase
|
46
|
+
@sio.string.must_equal "{increase}: 1\n{increase}: 2\n"
|
47
|
+
@l.num_events.must_equal 0
|
48
|
+
@l.num_events(:increase).must_equal 2
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'can return old default events' do
|
53
|
+
|
54
|
+
@l.log "event 1"
|
55
|
+
@l.event_descriptions.must_equal ["event 1"]
|
56
|
+
|
57
|
+
@l.log "event 2"
|
58
|
+
@l.event_descriptions.must_equal ["event 1", "event 2"]
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'can return old events of given type' do
|
63
|
+
|
64
|
+
@l.log "1", :increase
|
65
|
+
@l.log "2", :increase
|
66
|
+
@l.log "0.4", :alpha
|
67
|
+
@l.log "1", :increase
|
68
|
+
|
69
|
+
@l.event_descriptions(:increase).must_equal ["{increase}: 1", "{increase}: 2", "{increase}: 1"]
|
70
|
+
|
71
|
+
@l.event_descriptions(:alpha).must_equal ["{alpha}: 0.4"]
|
72
|
+
|
73
|
+
@l.event_descriptions(:beta).must_equal []
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'time stamps each log entry' do
|
78
|
+
|
79
|
+
@l.log "1", :a
|
80
|
+
@l.log "2", :b
|
81
|
+
@l.log "2", :a
|
82
|
+
|
83
|
+
time_stamps_a = @l.events(:a).map {|e| e.time_stamp}
|
84
|
+
time_stamps_b = @l.events(:b).map {|e| e.time_stamp}
|
85
|
+
|
86
|
+
time_stamps_a[0].must_be_instance_of Time
|
87
|
+
time_stamps_a[1].must_be_instance_of Time
|
88
|
+
time_stamps_b[0].must_be_instance_of Time
|
89
|
+
|
90
|
+
time_stamps_a[0].must_be :<, time_stamps_a[1]
|
91
|
+
time_stamps_a[0].must_be :<, time_stamps_b[0]
|
92
|
+
time_stamps_b[0].must_be :<, time_stamps_a[1]
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
data/test/test_statistics.rb
CHANGED
@@ -82,6 +82,18 @@ describe "Statistics" do
|
|
82
82
|
kde.densities[3].must_be_close_to 0.2728
|
83
83
|
end
|
84
84
|
end
|
85
|
+
|
86
|
+
describe "correlation between Ruby arrays" do
|
87
|
+
|
88
|
+
it "works for a simple example from the R doc for cor" do
|
89
|
+
correlation( (1..10).to_a, (2..11).to_a ).must_equal 1
|
90
|
+
end
|
91
|
+
|
92
|
+
it "works for the inverse of the simple example from the R doc for cor" do
|
93
|
+
correlation( (1..10).to_a, (-11..-2).to_a.reverse ).must_equal -1
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
85
97
|
end
|
86
98
|
|
87
99
|
require 'feldtruby/minitest_extensions'
|
@@ -154,7 +166,7 @@ describe "Plotting" do
|
|
154
166
|
|
155
167
|
File.exist?(out).must_equal true
|
156
168
|
|
157
|
-
|
169
|
+
File.delete out
|
158
170
|
|
159
171
|
end
|
160
172
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feldtruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.16
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rinruby
|
@@ -79,9 +79,11 @@ files:
|
|
79
79
|
- lib/feldtruby/array.rb
|
80
80
|
- lib/feldtruby/array/basic_stats.rb
|
81
81
|
- lib/feldtruby/array/count_by.rb
|
82
|
+
- lib/feldtruby/array/permutations_and_subsets.rb
|
82
83
|
- lib/feldtruby/file/file_change_watcher.rb
|
83
84
|
- lib/feldtruby/file/tempfile.rb
|
84
85
|
- lib/feldtruby/float.rb
|
86
|
+
- lib/feldtruby/logger.rb
|
85
87
|
- lib/feldtruby/math/rand.rb
|
86
88
|
- lib/feldtruby/minitest_extensions.rb
|
87
89
|
- lib/feldtruby/net/html_doc_getter.rb
|
@@ -115,11 +117,13 @@ files:
|
|
115
117
|
- test/test_array.rb
|
116
118
|
- test/test_array_basic_stats.rb
|
117
119
|
- test/test_array_count_by.rb
|
120
|
+
- test/test_array_permutations_and_subsets.rb
|
118
121
|
- test/test_clustering.rb
|
119
122
|
- test/test_euclidean_distance.rb
|
120
123
|
- test/test_fastmap.rb
|
121
124
|
- test/test_float.rb
|
122
125
|
- test/test_html_doc_getter.rb
|
126
|
+
- test/test_logger.rb
|
123
127
|
- test/test_normalization.rb
|
124
128
|
- test/test_optimize.rb
|
125
129
|
- test/test_optimize_differential_evolution.rb
|
@@ -165,11 +169,13 @@ test_files:
|
|
165
169
|
- test/test_array.rb
|
166
170
|
- test/test_array_basic_stats.rb
|
167
171
|
- test/test_array_count_by.rb
|
172
|
+
- test/test_array_permutations_and_subsets.rb
|
168
173
|
- test/test_clustering.rb
|
169
174
|
- test/test_euclidean_distance.rb
|
170
175
|
- test/test_fastmap.rb
|
171
176
|
- test/test_float.rb
|
172
177
|
- test/test_html_doc_getter.rb
|
178
|
+
- test/test_logger.rb
|
173
179
|
- test/test_normalization.rb
|
174
180
|
- test/test_optimize.rb
|
175
181
|
- test/test_optimize_differential_evolution.rb
|