modelfox 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +15 -0
- data/LICENSE +21 -0
- data/README.md +36 -0
- data/docs/Tangram/BagOfWordsCosineSimilarityFeatureContribution.html +518 -0
- data/docs/Tangram/BagOfWordsFeatureContribution.html +518 -0
- data/docs/Tangram/Bigram.html +370 -0
- data/docs/Tangram/BinaryClassificationPredictOutput.html +502 -0
- data/docs/Tangram/FeatureContributions.html +444 -0
- data/docs/Tangram/IdentityFeatureContribution.html +444 -0
- data/docs/Tangram/LibTangram/TangramStringView.html +193 -0
- data/docs/Tangram/LibTangram.html +161 -0
- data/docs/Tangram/LoadModelOptions.html +296 -0
- data/docs/Tangram/Model.html +1290 -0
- data/docs/Tangram/MulticlassClassificationPredictOutput.html +576 -0
- data/docs/Tangram/NormalizedFeatureContribution.html +444 -0
- data/docs/Tangram/OneHotEncodedFeatureContribution.html +518 -0
- data/docs/Tangram/PredictOptions.html +428 -0
- data/docs/Tangram/RegressionPredictOutput.html +428 -0
- data/docs/Tangram/Unigram.html +296 -0
- data/docs/Tangram/WordEmbeddingFeatureContribution.html +444 -0
- data/docs/Tangram.html +128 -0
- data/docs/_index.html +317 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +497 -0
- data/docs/file.README.html +107 -0
- data/docs/file_list.html +56 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +107 -0
- data/docs/js/app.js +314 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +595 -0
- data/docs/top-level-namespace.html +110 -0
- data/lib/modelfox/libmodelfox/aarch64-linux-gnu/libmodelfox.so +0 -0
- data/lib/modelfox/libmodelfox/aarch64-linux-musl/libmodelfox.so +0 -0
- data/lib/modelfox/libmodelfox/aarch64-macos/libmodelfox.dylib +0 -0
- data/lib/modelfox/libmodelfox/x86_64-linux-gnu/libmodelfox.so +0 -0
- data/lib/modelfox/libmodelfox/x86_64-linux-musl/libmodelfox.so +0 -0
- data/lib/modelfox/libmodelfox/x86_64-macos/libmodelfox.dylib +0 -0
- data/lib/modelfox/libmodelfox/x86_64-windows-msvc/modelfox.dll +0 -0
- data/lib/modelfox/modelfox.rb +895 -0
- data/lib/modelfox.rb +1 -0
- data/modelfox.gemspec +15 -0
- data/scripts/build +11 -0
- data/scripts/dev +6 -0
- data/scripts/docs +2 -0
- data/scripts/fmt +0 -0
- data/scripts/release +1 -0
- metadata +109 -0
@@ -0,0 +1,895 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'ffi'
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
# This is the main module in the `modelfox` gem.
|
8
|
+
module ModelFox
|
9
|
+
|
10
|
+
# These are the options passed when loading a model.
|
11
|
+
class LoadModelOptions
|
12
|
+
# If you are running the app locally or on your own server, use this field to provide the url to it. If not specified, the default value is https://app.modelfox.dev.
|
13
|
+
attr_reader :modelfox_url
|
14
|
+
def initialize(modelfox_url:)
|
15
|
+
@modelfox_url = modelfox_url
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# These are the options passed to `predict`.
|
20
|
+
class PredictOptions
|
21
|
+
# If your model is a binary classifier, use this field to make predictions using a threshold chosen on the tuning page of the app. The default value is `0.5`.
|
22
|
+
attr_reader :threshold
|
23
|
+
# Computing feature contributions is disabled by default. If you set this field to `true`, you will be able to access the feature contributions with the `feature_contributions` field of the predict output.
|
24
|
+
attr_reader :compute_feature_contributions
|
25
|
+
def initialize(compute_feature_contributions:, threshold: nil)
|
26
|
+
@threshold = threshold
|
27
|
+
@compute_feature_contributions = compute_feature_contributions
|
28
|
+
end
|
29
|
+
def to_json(*args)
|
30
|
+
{'threshold' => @threshold, 'compute_feature_contributions' => @compute_feature_contributions}.to_json(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# `predict` outputs `RegressionPredictOutput` when the model's task is regression.
|
35
|
+
class RegressionPredictOutput
|
36
|
+
# This is the predicted value.
|
37
|
+
attr_reader :value
|
38
|
+
# If computing feature contributions was enabled in the predict options, this value will explain the model's output, showing how much each feature contributed to the output.
|
39
|
+
attr_reader :feature_contributions
|
40
|
+
def initialize(value:, feature_contributions:)
|
41
|
+
@value = value
|
42
|
+
@feature_contributions = feature_contributions
|
43
|
+
end
|
44
|
+
def to_json(*args)
|
45
|
+
{'value' => @value}.to_json(*args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# `predict` outputs `BinaryClassificationPredictOutput` when the model's task is binary classification.
|
50
|
+
class BinaryClassificationPredictOutput
|
51
|
+
# This is the name of the predicted class.
|
52
|
+
attr_reader :class_name
|
53
|
+
# This is the probability the model assigned to the predicted class.
|
54
|
+
attr_reader :probability
|
55
|
+
# If computing feature contributions was enabled in the predict options, this value will explain the model's output, showing how much each feature contributed to the output.
|
56
|
+
attr_reader :feature_contributions
|
57
|
+
def initialize(class_name:, probability:, feature_contributions:)
|
58
|
+
@class_name = class_name
|
59
|
+
@probability = probability
|
60
|
+
@feature_contributions = feature_contributions
|
61
|
+
end
|
62
|
+
def to_json(*args)
|
63
|
+
{'class_name' => @class_name, "probability" => @probability}.to_json(*args)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# `predict` outputs `MulticlassClassificationPredictOutput` when the model's task is multiclass classification.
|
68
|
+
class MulticlassClassificationPredictOutput
|
69
|
+
# This is the name of the predicted class.
|
70
|
+
attr_reader :class_name
|
71
|
+
# This is the probability the model assigned to the predicted class.
|
72
|
+
attr_reader :probability
|
73
|
+
# This value maps from class names to the probability the model assigned to each class.
|
74
|
+
attr_reader :probabilities
|
75
|
+
# If computing feature contributions was enabled in the predict options, this value will explain the model's output, showing how much each feature contributed to the output. This value maps from class names to `FeatureContributions` values for each class. The class with the `FeatureContributions` value with the highest `output_value` is the predicted class.
|
76
|
+
attr_reader :feature_contributions
|
77
|
+
def initialize(class_name:, probability:, probabilities:, feature_contributions:)
|
78
|
+
@class_name = class_name
|
79
|
+
@probability = probability
|
80
|
+
@probabilities = probabilities
|
81
|
+
@feature_contributions = feature_contributions
|
82
|
+
end
|
83
|
+
def to_json(*args)
|
84
|
+
{'class_name' => @class_name, "probability" => @probability, "probabilities" => @probabilities}.to_json(*args)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# This is a description of the feature contributions for the prediction if the task is regression or binary classification, or for a single class if the task is multiclass classification.
|
89
|
+
class FeatureContributions
|
90
|
+
# This is the value the model would output if all features had baseline values.
|
91
|
+
attr_reader :baseline
|
92
|
+
# This is the value the model output. Any difference from the `baseline_value` is because of the deviation of the features from their baseline values.
|
93
|
+
attr_reader :output
|
94
|
+
# This list will contain one entry for each of the model's features. Note that features are computed from columns, so there will likely be more features than columns.
|
95
|
+
attr_reader :entries
|
96
|
+
def initialize(baseline:, output:, entries:)
|
97
|
+
@baseline = baseline
|
98
|
+
@output = output
|
99
|
+
@entries = entries
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# This describes the contribution of a feature from an identity feature group.
|
104
|
+
class IdentityFeatureContribution
|
105
|
+
# This is the name of the source column for the feature group.
|
106
|
+
attr_reader :column_name
|
107
|
+
# This is the value of the feature.
|
108
|
+
attr_reader :feature_value
|
109
|
+
# This is the amount that the feature contributed to the output.
|
110
|
+
attr_reader :feature_contribution_value
|
111
|
+
def initialize(column_name:, feature_contribution_value:, feature_value:)
|
112
|
+
@column_name = column_name
|
113
|
+
@feature_value = feature_value
|
114
|
+
@feature_contribution_value = feature_contribution_value
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# This describes the contribution of a feature from a normalized feature group.
|
119
|
+
class NormalizedFeatureContribution
|
120
|
+
# This is the name of the source column for the feature group.
|
121
|
+
attr_reader :column_name
|
122
|
+
# This is the value of the feature.
|
123
|
+
attr_reader :feature_value
|
124
|
+
# This is the amount that the feature contributed to the output.
|
125
|
+
attr_reader :feature_contribution_value
|
126
|
+
def initialize(column_name:, feature_value:, feature_contribution_value:)
|
127
|
+
@column_name = column_name
|
128
|
+
@feature_value = feature_value
|
129
|
+
@feature_contribution_value = feature_contribution_value
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# This describes the contribution of a feature from a one hot encoded feature group.
|
134
|
+
class OneHotEncodedFeatureContribution
|
135
|
+
# This is the name of the source column for the feature group.
|
136
|
+
attr_reader :column_name
|
137
|
+
# This is the enum variant the feature indicates the presence of.
|
138
|
+
attr_reader :variant
|
139
|
+
# This is the value of the feature.
|
140
|
+
attr_reader :feature_value
|
141
|
+
# This is the amount that the feature contributed to the output.b
|
142
|
+
attr_reader :feature_contribution_value
|
143
|
+
def initialize(column_name:, variant:, feature_contribution_value:, feature_value:)
|
144
|
+
@column_name = column_name
|
145
|
+
@variant = variant
|
146
|
+
@feature_contribution_value = feature_contribution_value
|
147
|
+
@feature_value = feature_value
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# This describes the contribution of a feature from a bag of words feature group.
|
152
|
+
class BagOfWordsFeatureContribution
|
153
|
+
# This is the name of the source column for the feature group.
|
154
|
+
attr_reader :column_name
|
155
|
+
# This is the ngram for the feature.
|
156
|
+
attr_reader :ngram
|
157
|
+
# This is the value of the feature.
|
158
|
+
attr_reader :feature_value
|
159
|
+
# This is the amount that the feature contributed to the output.
|
160
|
+
attr_reader :feature_contribution_value
|
161
|
+
def initialize(column_name:, ngram:, feature_contribution_value:, feature_value:)
|
162
|
+
@column_name = column_name
|
163
|
+
@ngram = ngram
|
164
|
+
@feature_contribution_value = feature_contribution_value
|
165
|
+
@feature_value = feature_value
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# This describes a unigram ngram.
|
170
|
+
class Unigram
|
171
|
+
# This is the token.
|
172
|
+
attr_reader :token
|
173
|
+
def initialize(token)
|
174
|
+
@token = token
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# This describes a bigram ngram.
|
179
|
+
class Bigram
|
180
|
+
# This is the first token in the bigram.
|
181
|
+
attr_reader :token_a
|
182
|
+
# This is the second token in the bigram.
|
183
|
+
attr_reader :token_b
|
184
|
+
def initialize(token_a:, token_b:)
|
185
|
+
@token_a = token_a
|
186
|
+
@token_b = token_b
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# This describes the contribution of a feature from a bag of words cosine similarity feature group.
|
191
|
+
class BagOfWordsCosineSimilarityFeatureContribution
|
192
|
+
# This is the name of the source column a for the feature group.
|
193
|
+
attr_reader :column_name_a
|
194
|
+
# This is the name of the source column b for the feature group.
|
195
|
+
attr_reader :column_name_b
|
196
|
+
# This is the value of the feature.
|
197
|
+
attr_reader :feature_value
|
198
|
+
# This is the amount that the feature contributed to the output.
|
199
|
+
attr_reader :feature_contribution_value
|
200
|
+
def initialize(column_name_a:, column_name_b:, feature_contribution_value:, feature_value:)
|
201
|
+
@column_name_a = column_name_a
|
202
|
+
@column_name_b = column_name_b
|
203
|
+
@feature_contribution_value = feature_contribution_value
|
204
|
+
@feature_value = feature_value
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# This describes the contribution of a feature from a word embedding feature group.
|
209
|
+
class WordEmbeddingFeatureContribution
|
210
|
+
# This is the name of the source column for the feature group.
|
211
|
+
attr_reader :column_name
|
212
|
+
# This is the index of the feature in the word embedding.
|
213
|
+
attr_reader :value_index
|
214
|
+
# This is the amount that the feature contributed to the output.
|
215
|
+
attr_reader :feature_contribution_value
|
216
|
+
def initialize(column_name:, value_index:, feature_contribution_value:)
|
217
|
+
@column_name = column_name
|
218
|
+
@value_index = value_index
|
219
|
+
@feature_contribution_value = feature_contribution_value
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Use this class to load a model, make predictions, and log events to the app.
|
224
|
+
class Model
|
225
|
+
# Load a model from the `.modelfox` file at `path`.
|
226
|
+
# @param path [String] The path to the `.modelfox` file.
|
227
|
+
# @param options [LoadModelOptions] The options to use when loading the model.
|
228
|
+
# @return [Model]
|
229
|
+
def self.from_path(path, options: nil)
|
230
|
+
c_model = FFI::MemoryPointer.new(:pointer)
|
231
|
+
c_err = LibModelFox.modelfox_model_from_path(path, c_model)
|
232
|
+
unless c_err.null?
|
233
|
+
c_err = FFI::AutoPointer.new(c_err, LibModelFox.method(:modelfox_error_delete))
|
234
|
+
c_error_s = LibModelFox::ModelFoxStringView.new
|
235
|
+
LibModelFox.modelfox_error_get_message(c_err, c_error_s)
|
236
|
+
raise c_error_s.into_string
|
237
|
+
end
|
238
|
+
new(c_model, options: options)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Load a model from bytes instead of a file. You should use this only if you already have a `.modelfox` loaded into memory. Otherwise, use `Model.from_path`, which is faster because it memory maps the file.
|
242
|
+
# @param bytes [String] The bytes for the .modelfox model.
|
243
|
+
# @param options [LoadModelOptions] The options to use when loading the model.
|
244
|
+
# @return [Model]
|
245
|
+
def self.from_bytes(bytes, options: nil)
|
246
|
+
c_model = FFI::MemoryPointer.new(:pointer)
|
247
|
+
c_err = LibModelFox.modelfox_model_from_bytes(bytes, bytes.size, c_model)
|
248
|
+
unless err.null?
|
249
|
+
c_err = FFI::AutoPointer.new(c_err, LibModelFox.method(:modelfox_error_delete))
|
250
|
+
c_error_s = LibModelFox::ModelFoxStringView.new
|
251
|
+
LibModelFox.modelfox_error_get_message(c_err, c_error_s)
|
252
|
+
raise errors.into_string
|
253
|
+
end
|
254
|
+
new(c_model, options: options)
|
255
|
+
end
|
256
|
+
|
257
|
+
def initialize(c_model, options: nil)
|
258
|
+
@modelfox_url = options&.modelfox_url.nil? ? 'https://app.modelfox.dev' : options&.modelfox_url
|
259
|
+
@log_queue = []
|
260
|
+
@model = FFI::AutoPointer.new(c_model.read_pointer, LibModelFox.method(:modelfox_model_delete))
|
261
|
+
end
|
262
|
+
|
263
|
+
# Retrieve the model's id.
|
264
|
+
def id
|
265
|
+
c_id = LibModelFox::ModelFoxStringView.new
|
266
|
+
LibModelFox.modelfox_model_get_id(@model, c_id)
|
267
|
+
c_id.into_string
|
268
|
+
end
|
269
|
+
|
270
|
+
# Make a prediction!
|
271
|
+
# @param input [Array<Hash{String, Symbol => String, Number}>, Hash{String, Symbol => String, Number}] A predict input is either a single predict input which is a map from symbols or strings to strings or floats or an array of such maps. The keys should match the columns in the CSV file you trained your model with.
|
272
|
+
# @param options [PredictOptions] These are the predict options.
|
273
|
+
# @return [Array<RegressionPredictOutput, BinaryClassificationPredictOutput, MulticlassClassificationPredictOutput>, RegressionPredictOutput, BinaryClassificationPredictOutput, MulticlassClassificationPredictOutput]. Return a single output if `input` was a single input, or an array if `input` was an array of `input`s.
|
274
|
+
def predict(input, options: nil)
|
275
|
+
is_array = input.is_a?(Array)
|
276
|
+
input = is_array ? input : [input]
|
277
|
+
c_input_vec = new_predict_input_vec(input)
|
278
|
+
c_options = new_predict_options(options)
|
279
|
+
c_output_vec = FFI::MemoryPointer.new(:pointer)
|
280
|
+
c_error = LibModelFox.modelfox_model_predict(@model, c_input_vec, c_options, c_output_vec)
|
281
|
+
raise 'modelfox error' unless c_error.null?
|
282
|
+
c_output_vec = FFI::AutoPointer.new(c_output_vec.read_pointer, LibModelFox.method(:modelfox_predict_output_vec_delete))
|
283
|
+
output = predict_output_vec_from_modelfox_predict_output_vec(c_output_vec)
|
284
|
+
is_array ? output : output[0]
|
285
|
+
end
|
286
|
+
|
287
|
+
# Send a prediction event to the app. If you want to batch events, you can use `enqueue_log_prediction` instead.
|
288
|
+
# @param identifier [String, Number] This is a unique identifier for the prediction, which will associate it with a true value event and allow you to look it up in the app.
|
289
|
+
# @param input [Hash{String, Symbol => String, Number}] A single `PredictInput`.
|
290
|
+
# @param output [PredictOutput] A single `PredictOutput`.
|
291
|
+
# @param options [PredictOptions] This is the same `predictOptions` value that you passed to `predict`.
|
292
|
+
def log_prediction(identifier:, input:, output:, options: nil)
|
293
|
+
event = prediction_event(
|
294
|
+
identifier: identifier,
|
295
|
+
input: input,
|
296
|
+
output: output,
|
297
|
+
options: options
|
298
|
+
)
|
299
|
+
log_event(event)
|
300
|
+
end
|
301
|
+
|
302
|
+
# Add a prediction event to the queue. Remember to call `flush_log_queue` at a later point to send the event to the app.
|
303
|
+
# @param identifier [String, Number] This is a unique identifier for the prediction, which will associate it with a true value event and allow you to look it up in the app.
|
304
|
+
# @param input [Hash{String, Symbol => String, Number}] A single `PredictInput`.
|
305
|
+
# @param output [PredictOutput] A single `PredictOutput`.
|
306
|
+
# @param options [PredictOptions] This is the same `predictOptions` value that you passed to `predict`.
|
307
|
+
def enqueue_log_prediction(identifier:, input:, output:, options: nil)
|
308
|
+
event = prediction_event(
|
309
|
+
identifier: identifier,
|
310
|
+
input: input,
|
311
|
+
output: output,
|
312
|
+
options: options
|
313
|
+
)
|
314
|
+
log_queue.push(event)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Send a true value event to the app. If you want to batch events, you can use `enqueue_log_true_value` instead.
|
318
|
+
# @param identifier [String, Number] This is a unique identifier for the prediction, which will associate it with a true value event and allow you to look it up in the app.
|
319
|
+
# @param true_value [String, Number] This is the true value for the prediction.
|
320
|
+
def log_true_value(identifier:, true_value:)
|
321
|
+
event = true_value_event(
|
322
|
+
identifier: identifier,
|
323
|
+
true_value: true_value
|
324
|
+
)
|
325
|
+
log_event(event)
|
326
|
+
end
|
327
|
+
|
328
|
+
# Add a true value event to the queue. Remember to call `flush_log_queue` at a later point to send the event to the app.
|
329
|
+
# @param identifier [String, Number] This is a unique identifier for the prediction, which will associate it with a true value event and allow you to look it up in the app.
|
330
|
+
# @param true_value [String, Number] This is the true value for the prediction.
|
331
|
+
def enqueue_log_true_value(identifier:, true_value:)
|
332
|
+
event = true_value_event(
|
333
|
+
identifier: identifier,
|
334
|
+
true_value: true_value
|
335
|
+
)
|
336
|
+
log_queue.push(event)
|
337
|
+
end
|
338
|
+
|
339
|
+
# Send all events in the queue to the app.
|
340
|
+
def flush_log_queue
|
341
|
+
log_events(@log_queue)
|
342
|
+
@log_queue = []
|
343
|
+
end
|
344
|
+
|
345
|
+
private
|
346
|
+
|
347
|
+
def log_event(event)
|
348
|
+
log_events([event])
|
349
|
+
end
|
350
|
+
|
351
|
+
def log_events(events)
|
352
|
+
headers = {
|
353
|
+
'Content-Type': 'application/json'
|
354
|
+
}
|
355
|
+
uri = URI("#{@modelfox_url}/track")
|
356
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
357
|
+
request = Net::HTTP::Post.new(uri.request_uri, headers)
|
358
|
+
request.body = events.to_json
|
359
|
+
response = http.request(request)
|
360
|
+
raise response unless response.is_a? Net::HTTPSuccess
|
361
|
+
end
|
362
|
+
|
363
|
+
def prediction_event(identifier:, input:, output:, options: nil)
|
364
|
+
{
|
365
|
+
date: DateTime.now.rfc3339,
|
366
|
+
identifier: identifier,
|
367
|
+
input: input,
|
368
|
+
model_id: id,
|
369
|
+
options: options,
|
370
|
+
output: output,
|
371
|
+
type: 'prediction'
|
372
|
+
}
|
373
|
+
end
|
374
|
+
|
375
|
+
def true_value_event(identifier:, true_value:)
|
376
|
+
{
|
377
|
+
date: DateTime.now.rfc3339,
|
378
|
+
identifier: identifier,
|
379
|
+
model_id: id,
|
380
|
+
true_value: true_value,
|
381
|
+
type: 'true_value'
|
382
|
+
}
|
383
|
+
end
|
384
|
+
|
385
|
+
def new_predict_options(options)
|
386
|
+
c_options = FFI::MemoryPointer.new(:pointer)
|
387
|
+
LibModelFox.modelfox_predict_options_new(c_options)
|
388
|
+
c_options = FFI::AutoPointer.new(c_options.read_pointer, LibModelFox.method(:modelfox_predict_options_delete))
|
389
|
+
unless options.nil?
|
390
|
+
unless options.threshold.nil?
|
391
|
+
LibModelFox.modelfox_predict_options_set_threshold(c_options, options.threshold)
|
392
|
+
end
|
393
|
+
unless options.compute_feature_contributions.nil?
|
394
|
+
LibModelFox.modelfox_predict_options_set_compute_feature_contributions(c_options, options.compute_feature_contributions)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
c_options
|
398
|
+
end
|
399
|
+
|
400
|
+
def new_predict_input_vec(input_vec)
|
401
|
+
c_inputs = FFI::MemoryPointer.new(:pointer)
|
402
|
+
LibModelFox.modelfox_predict_input_vec_new(c_inputs)
|
403
|
+
c_inputs = FFI::AutoPointer.new(c_inputs.read_pointer, LibModelFox.method(:modelfox_predict_input_vec_delete))
|
404
|
+
(0...input_vec.length).each do |input_index|
|
405
|
+
input = input_vec[input_index]
|
406
|
+
predict_input = new_predict_input(input)
|
407
|
+
LibModelFox.modelfox_predict_input_vec_push(c_inputs, predict_input)
|
408
|
+
end
|
409
|
+
c_inputs
|
410
|
+
end
|
411
|
+
|
412
|
+
def new_predict_input(input)
|
413
|
+
c_input = FFI::MemoryPointer.new(:pointer)
|
414
|
+
LibModelFox.modelfox_predict_input_new(c_input)
|
415
|
+
c_input = c_input.read_pointer
|
416
|
+
input.each do |key, value|
|
417
|
+
is_float = value.is_a?(Float)
|
418
|
+
is_string = value.is_a?(String)
|
419
|
+
if is_float
|
420
|
+
LibModelFox.modelfox_predict_input_set_value_number(c_input, key.to_s, value)
|
421
|
+
elsif is_string
|
422
|
+
LibModelFox.modelfox_predict_input_set_value_string(c_input, key.to_s, value)
|
423
|
+
else
|
424
|
+
raise 'value for key %s is not a float or a string' % key
|
425
|
+
end
|
426
|
+
end
|
427
|
+
c_input
|
428
|
+
end
|
429
|
+
|
430
|
+
def predict_output_vec_from_modelfox_predict_output_vec(c_output_vec)
|
431
|
+
outputs = []
|
432
|
+
c_output_len = FFI::MemoryPointer.new(:int)
|
433
|
+
LibModelFox.modelfox_predict_output_vec_len(c_output_vec, c_output_len)
|
434
|
+
output_len = c_output_len.read(:int)
|
435
|
+
(0...output_len).each do |output_index|
|
436
|
+
c_output = FFI::MemoryPointer.new(:pointer)
|
437
|
+
LibModelFox.modelfox_predict_output_vec_get_at_index(c_output_vec, output_index, c_output)
|
438
|
+
c_output = c_output.read_pointer
|
439
|
+
outputs.push(predict_output_from_modelfox_predict_output(c_output))
|
440
|
+
end
|
441
|
+
|
442
|
+
outputs
|
443
|
+
end
|
444
|
+
|
445
|
+
def predict_output_from_modelfox_predict_output(c_output)
|
446
|
+
c_task_type = FFI::MemoryPointer.new(:int)
|
447
|
+
LibModelFox.modelfox_model_get_task(@model, c_task_type)
|
448
|
+
case c_task_type.read(:int)
|
449
|
+
when LibModelFox::ModelFoxTaskType[:regression]
|
450
|
+
regression_output_from_modelfox_predict_output(c_output)
|
451
|
+
when LibModelFox::ModelFoxTaskType[:binary_classification]
|
452
|
+
binary_classification_output_from_modelfox_predict_output(c_output)
|
453
|
+
when LibModelFox::ModelFoxTaskType[:multiclass_classification]
|
454
|
+
multiclass_classification_output_from_modelfox_predict_output(c_output)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def regression_output_from_modelfox_predict_output(c_output)
|
459
|
+
c_regression_output = FFI::MemoryPointer.new(:pointer)
|
460
|
+
LibModelFox.modelfox_predict_output_as_regression(c_output, c_regression_output)
|
461
|
+
c_regression_output = c_regression_output.read_pointer
|
462
|
+
c_value = FFI::MemoryPointer.new(:float)
|
463
|
+
LibModelFox.modelfox_regression_predict_output_get_value(c_regression_output, c_value)
|
464
|
+
value = c_value.read(:float)
|
465
|
+
c_feature_contributions = FFI::MemoryPointer.new(:pointer)
|
466
|
+
LibModelFox.modelfox_regression_predict_output_get_feature_contributions(c_regression_output, c_feature_contributions)
|
467
|
+
c_feature_contributions = c_feature_contributions.read_pointer
|
468
|
+
feature_contributions = c_feature_contributions.null? ? {} : get_feature_contributions(c_feature_contributions)
|
469
|
+
RegressionPredictOutput.new(
|
470
|
+
value: value,
|
471
|
+
feature_contributions: feature_contributions
|
472
|
+
)
|
473
|
+
end
|
474
|
+
|
475
|
+
def binary_classification_output_from_modelfox_predict_output(c_output)
|
476
|
+
c_binary_classification_output = FFI::MemoryPointer.new(:pointer)
|
477
|
+
LibModelFox.modelfox_predict_output_as_binary_classification(c_output, c_binary_classification_output)
|
478
|
+
c_binary_classification_output = c_binary_classification_output.read_pointer
|
479
|
+
c_probability = FFI::MemoryPointer.new(:float)
|
480
|
+
LibModelFox.modelfox_binary_classification_predict_output_get_probability(c_binary_classification_output, c_probability)
|
481
|
+
probability = c_probability.read(:float)
|
482
|
+
c_class_name = LibModelFox::ModelFoxStringView.new
|
483
|
+
LibModelFox.modelfox_binary_classification_predict_output_get_class_name(c_binary_classification_output, c_class_name)
|
484
|
+
class_name = c_class_name.into_string
|
485
|
+
c_feature_contributions = FFI::MemoryPointer.new(:pointer)
|
486
|
+
LibModelFox.modelfox_binary_classification_predict_output_get_feature_contributions(c_binary_classification_output, c_feature_contributions)
|
487
|
+
c_feature_contributions = c_feature_contributions.read_pointer
|
488
|
+
feature_contributions = c_feature_contributions.null? ? {} : get_feature_contributions(c_feature_contributions)
|
489
|
+
BinaryClassificationPredictOutput.new(
|
490
|
+
class_name: class_name,
|
491
|
+
probability: probability,
|
492
|
+
feature_contributions: feature_contributions
|
493
|
+
)
|
494
|
+
end
|
495
|
+
|
496
|
+
def multiclass_classification_output_from_modelfox_predict_output(c_output)
|
497
|
+
c_multiclass_classification_output = FFI::MemoryPointer.new(:pointer)
|
498
|
+
LibModelFox.modelfox_predict_output_as_multiclass_classification(c_output, c_multiclass_classification_output)
|
499
|
+
c_multiclass_classification_output = c_multiclass_classification_output.read_pointer
|
500
|
+
c_probability = FFI::MemoryPointer.new(:float)
|
501
|
+
LibModelFox.modelfox_multiclass_classification_predict_output_get_probability(c_multiclass_classification_output, c_probability)
|
502
|
+
probability = c_probability.read(:float)
|
503
|
+
c_class_name = LibModelFox::ModelFoxStringView.new
|
504
|
+
LibModelFox.modelfox_multiclass_classification_predict_output_get_class_name(c_multiclass_classification_output, c_class_name)
|
505
|
+
class_name = c_class_name.into_string
|
506
|
+
probabilities = multiclass_classification_output_get_probabilities(c_multiclass_classification_output)
|
507
|
+
feature_contributions = multiclass_classification_output_get_feature_contributions(c_multiclass_classification_output)
|
508
|
+
MulticlassClassificationPredictOutput.new(
|
509
|
+
class_name: class_name,
|
510
|
+
probability: probability,
|
511
|
+
probabilities: probabilities,
|
512
|
+
feature_contributions: feature_contributions
|
513
|
+
)
|
514
|
+
end
|
515
|
+
|
516
|
+
def multiclass_classification_output_get_probabilities(c_multiclass_classification_output)
|
517
|
+
probabilities = {}
|
518
|
+
c_probabilities_iter = FFI::MemoryPointer.new(:pointer)
|
519
|
+
LibModelFox.modelfox_multiclass_classification_predict_output_get_probabilities_iter(c_multiclass_classification_output, c_probabilities_iter)
|
520
|
+
c_probabilities_iter = FFI::AutoPointer.new(c_probabilities_iter.read_pointer, LibModelFox.method(:modelfox_multiclass_classification_predict_output_probabilities_iter_delete))
|
521
|
+
c_class_probability = FFI::MemoryPointer.new(:float)
|
522
|
+
c_class_name = LibModelFox::ModelFoxStringView.new
|
523
|
+
while LibModelFox.modelfox_multiclass_classification_predict_output_probabilities_iter_next(c_probabilities_iter, c_class_name, c_class_probability)
|
524
|
+
class_name = c_class_name.into_string
|
525
|
+
probabilities[class_name] = c_class_probability.read(:float)
|
526
|
+
end
|
527
|
+
probabilities
|
528
|
+
end
|
529
|
+
|
530
|
+
def multiclass_classification_output_get_feature_contributions(c_multiclass_classification_output)
|
531
|
+
c_feature_contributions_iter = FFI::MemoryPointer.new(:pointer)
|
532
|
+
LibModelFox.modelfox_multiclass_classification_predict_output_get_feature_contributions_iter(c_multiclass_classification_output, c_feature_contributions_iter)
|
533
|
+
c_feature_contributions_iter = FFI::AutoPointer.new(c_feature_contributions_iter.read_pointer, LibModelFox.method(:modelfox_multiclass_classification_predict_output_feature_contributions_iter_delete))
|
534
|
+
feature_contributions = {}
|
535
|
+
unless c_feature_contributions_iter.null?
|
536
|
+
c_class_name = LibModelFox::ModelFoxStringView.new
|
537
|
+
c_feature_contributions_ptr = FFI::MemoryPointer.new(:pointer)
|
538
|
+
while LibModelFox.modelfox_multiclass_classification_predict_output_feature_contributions_iter_next(c_feature_contributions_iter, c_class_name, c_feature_contributions_ptr)
|
539
|
+
class_name = c_class_name.into_string
|
540
|
+
c_feature_contributions = c_feature_contributions_ptr.read_pointer
|
541
|
+
unless c_feature_contributions.null?
|
542
|
+
feature_contributions[class_name] = get_feature_contributions(c_feature_contributions)
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
feature_contributions
|
547
|
+
end
|
548
|
+
|
549
|
+
def get_feature_contributions(c_feature_contributions)
|
550
|
+
c_baseline = FFI::MemoryPointer.new(:float)
|
551
|
+
LibModelFox.modelfox_feature_contributions_get_baseline_value(c_feature_contributions, c_baseline)
|
552
|
+
baseline = c_baseline.read(:float)
|
553
|
+
c_output = FFI::MemoryPointer.new(:float)
|
554
|
+
LibModelFox.modelfox_feature_contributions_get_output_value(c_feature_contributions, c_output)
|
555
|
+
output = c_output.read(:float)
|
556
|
+
feature_contribution_entries = get_feature_contributions_entries(c_feature_contributions)
|
557
|
+
FeatureContributions.new(
|
558
|
+
baseline: baseline,
|
559
|
+
output: output,
|
560
|
+
entries: feature_contribution_entries
|
561
|
+
)
|
562
|
+
end
|
563
|
+
|
564
|
+
def get_feature_contributions_entries(c_feature_contributions)
|
565
|
+
c_len = FFI::MemoryPointer.new(:int)
|
566
|
+
LibModelFox.modelfox_feature_contributions_get_entries_len(c_feature_contributions, c_len)
|
567
|
+
len = c_len.read(:int)
|
568
|
+
feature_contributions = []
|
569
|
+
(0...len).each do |i|
|
570
|
+
c_feature_contribution = FFI::MemoryPointer.new(:pointer)
|
571
|
+
LibModelFox.modelfox_feature_contributions_get_entry_at_index(c_feature_contributions, i, c_feature_contribution)
|
572
|
+
c_feature_contribution = c_feature_contribution.read_pointer
|
573
|
+
feature_contributions.push(get_feature_contribution(c_feature_contribution))
|
574
|
+
end
|
575
|
+
feature_contributions
|
576
|
+
end
|
577
|
+
|
578
|
+
def get_feature_contribution(c_feature_contribution)
|
579
|
+
c_feature_contribution_type = FFI::MemoryPointer.new(:int)
|
580
|
+
LibModelFox.modelfox_feature_contribution_entry_get_type(c_feature_contribution, c_feature_contribution_type)
|
581
|
+
case c_feature_contribution_type.read(:int)
|
582
|
+
when LibModelFox::ModelFoxFeatureContributionEntryType[:identity]
|
583
|
+
get_identity_feature_contribution(c_feature_contribution)
|
584
|
+
when LibModelFox::ModelFoxFeatureContributionEntryType[:normalized]
|
585
|
+
get_normalized_feature_contribution(c_feature_contribution)
|
586
|
+
when LibModelFox::ModelFoxFeatureContributionEntryType[:one_hot_encoded]
|
587
|
+
get_one_hot_encoded_feature_contribution(c_feature_contribution)
|
588
|
+
when LibModelFox::ModelFoxFeatureContributionEntryType[:bag_of_words]
|
589
|
+
get_bag_of_words_feature_contribution(c_feature_contribution)
|
590
|
+
when LibModelFox::ModelFoxFeatureContributionEntryType[:bag_of_words_cosine_similarity]
|
591
|
+
get_bag_of_words_cosine_similarity_feature_contribution(c_feature_contribution)
|
592
|
+
when LibModelFox::ModelFoxFeatureContributionEntryType[:word_embedding]
|
593
|
+
get_word_embedding_feature_contribution(c_feature_contribution)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
def get_identity_feature_contribution(c_feature_contribution)
|
598
|
+
c_identity_feature_contribution = FFI::MemoryPointer.new(:pointer)
|
599
|
+
LibModelFox.modelfox_feature_contribution_entry_as_identity(c_feature_contribution, c_identity_feature_contribution)
|
600
|
+
c_identity_feature_contribution = c_identity_feature_contribution.read_pointer
|
601
|
+
c_column_name = LibModelFox::ModelFoxStringView.new
|
602
|
+
LibModelFox.modelfox_identity_feature_contribution_get_column_name(c_identity_feature_contribution, c_column_name)
|
603
|
+
column_name = c_column_name.into_string
|
604
|
+
c_feature_contribution_value = FFI::MemoryPointer.new(:float)
|
605
|
+
LibModelFox.modelfox_identity_feature_contribution_get_feature_contribution_value(c_identity_feature_contribution, c_feature_contribution_value)
|
606
|
+
feature_contribution_value = c_feature_contribution_value.read(:float)
|
607
|
+
c_feature_value = FFI::MemoryPointer.new(:float)
|
608
|
+
LibModelFox.modelfox_identity_feature_contribution_get_feature_value(c_identity_feature_contribution, c_feature_value)
|
609
|
+
feature_value = c_feature_value.read(:float)
|
610
|
+
IdentityFeatureContribution.new(
|
611
|
+
column_name: column_name,
|
612
|
+
feature_value: feature_value,
|
613
|
+
feature_contribution_value: feature_contribution_value
|
614
|
+
)
|
615
|
+
end
|
616
|
+
|
617
|
+
def get_normalized_feature_contribution(c_feature_contribution)
|
618
|
+
c_normalized_feature_contribution = FFI::MemoryPointer.new(:pointer)
|
619
|
+
LibModelFox.modelfox_feature_contribution_entry_as_normalized(
|
620
|
+
c_feature_contribution, c_normalized_feature_contribution
|
621
|
+
)
|
622
|
+
c_normalized_feature_contribution = c_normalized_feature_contribution.read_pointer
|
623
|
+
c_column_name = LibModelFox::ModelFoxStringView.new
|
624
|
+
LibModelFox.modelfox_normalized_feature_contribution_get_column_name(c_normalized_feature_contribution, c_column_name)
|
625
|
+
column_name = c_column_name.into_string
|
626
|
+
c_feature_value = FFI::MemoryPointer.new(:float)
|
627
|
+
LibModelFox.modelfox_normalized_feature_contribution_get_feature_value(c_normalized_feature_contribution, c_feature_value)
|
628
|
+
feature_value = c_feature_value.read(:float)
|
629
|
+
c_feature_contribution_value = FFI::MemoryPointer.new(:float)
|
630
|
+
LibModelFox.modelfox_normalized_feature_contribution_get_feature_contribution_value(c_normalized_feature_contribution, c_feature_contribution_value)
|
631
|
+
feature_contribution_value = c_feature_contribution_value.read(:float)
|
632
|
+
NormalizedFeatureContribution.new(
|
633
|
+
column_name: column_name,
|
634
|
+
feature_value: feature_value,
|
635
|
+
feature_contribution_value: feature_contribution_value
|
636
|
+
)
|
637
|
+
end
|
638
|
+
|
639
|
+
def get_one_hot_encoded_feature_contribution(c_feature_contribution)
|
640
|
+
c_one_hot_encoded_feature_contribution = FFI::MemoryPointer.new(:pointer)
|
641
|
+
LibModelFox.modelfox_feature_contribution_entry_as_one_hot_encoded(c_feature_contribution, c_one_hot_encoded_feature_contribution)
|
642
|
+
c_one_hot_encoded_feature_contribution = c_one_hot_encoded_feature_contribution.read_pointer
|
643
|
+
c_column_name = LibModelFox::ModelFoxStringView.new
|
644
|
+
LibModelFox.modelfox_one_hot_encoded_feature_contribution_get_column_name(c_one_hot_encoded_feature_contribution, c_column_name)
|
645
|
+
column_name = c_column_name.into_string
|
646
|
+
c_feature_contribution_value = FFI::MemoryPointer.new(:float)
|
647
|
+
LibModelFox.modelfox_one_hot_encoded_feature_contribution_get_feature_contribution_value(c_one_hot_encoded_feature_contribution, c_feature_contribution_value)
|
648
|
+
feature_contribution_value = c_feature_contribution_value.read(:float)
|
649
|
+
c_feature_value = FFI::MemoryPointer.new(:bool)
|
650
|
+
LibModelFox.modelfox_one_hot_encoded_feature_contribution_get_feature_value(c_one_hot_encoded_feature_contribution, c_feature_value)
|
651
|
+
feature_value = c_feature_value.read(:bool)
|
652
|
+
c_variant = LibModelFox::ModelFoxStringView.new
|
653
|
+
LibModelFox.modelfox_one_hot_encoded_feature_contribution_get_variant(c_one_hot_encoded_feature_contribution, c_variant)
|
654
|
+
variant = c_variant[:ptr].null? ? nil : c_variant.into_string
|
655
|
+
OneHotEncodedFeatureContribution.new(
|
656
|
+
column_name: column_name,
|
657
|
+
variant: variant,
|
658
|
+
feature_contribution_value: feature_contribution_value,
|
659
|
+
feature_value: feature_value
|
660
|
+
)
|
661
|
+
end
|
662
|
+
|
663
|
+
def get_bag_of_words_feature_contribution(c_feature_contribution)
|
664
|
+
c_bag_of_words_feature_contribution = FFI::MemoryPointer.new(:pointer)
|
665
|
+
LibModelFox.modelfox_feature_contribution_entry_as_bag_of_words(c_feature_contribution, c_bag_of_words_feature_contribution)
|
666
|
+
c_bag_of_words_feature_contribution = c_bag_of_words_feature_contribution.read_pointer
|
667
|
+
c_column_name = LibModelFox::ModelFoxStringView.new
|
668
|
+
LibModelFox.modelfox_bag_of_words_feature_contribution_get_column_name(c_bag_of_words_feature_contribution, c_column_name)
|
669
|
+
column_name = c_column_name.into_string
|
670
|
+
c_feature_contribution_value = FFI::MemoryPointer.new(:float)
|
671
|
+
LibModelFox.modelfox_bag_of_words_feature_contribution_get_feature_contribution_value(c_bag_of_words_feature_contribution, c_feature_contribution_value)
|
672
|
+
feature_contribution_value = c_feature_contribution_value.read(:float)
|
673
|
+
c_feature_value = FFI::MemoryPointer.new(:float)
|
674
|
+
LibModelFox.modelfox_bag_of_words_feature_contribution_get_feature_value(c_bag_of_words_feature_contribution, c_feature_value)
|
675
|
+
feature_value = c_feature_value.read(:float)
|
676
|
+
c_ngram = FFI::MemoryPointer(:pointer)
|
677
|
+
LibModelFox.modelfox_bag_of_words_feature_contribution_get_ngram(c_bag_of_words_feature_contribution, c_ngram)
|
678
|
+
c_ngram = c_ngram.read_pointer
|
679
|
+
ngram = get_ngram(c_ngram)
|
680
|
+
BagOfWordsFeatureContribution.new(
|
681
|
+
column_name: column_name,
|
682
|
+
ngram: ngram,
|
683
|
+
feature_contribution_value: feature_contribution_value,
|
684
|
+
feature_value: feature_value
|
685
|
+
)
|
686
|
+
end
|
687
|
+
|
688
|
+
def get_bag_of_words_cosine_similarity_feature_contribution(c_feature_contribution)
|
689
|
+
c_bag_of_words_cosine_similarity_feature_contribution = FFI::MemoryPointer.new(:pointer)
|
690
|
+
LibModelFox.modelfox_feature_contribution_entry_as_bag_of_words_cosine_similarity(c_feature_contribution, c_bag_of_words_cosine_similarity_feature_contribution)
|
691
|
+
c_bag_of_words_cosine_similarity_feature_contribution = c_bag_of_words_cosine_similarity_feature_contribution.read_pointer
|
692
|
+
c_column_name_a = LibModelFox::ModelFoxStringView.new
|
693
|
+
LibModelFox.modelfox_bag_of_words_feature_contribution_get_column_name_a(c_bag_of_words_cosine_similarity_feature_contribution, c_column_name_a)
|
694
|
+
column_name_a = c_column_name_a.into_string
|
695
|
+
c_column_name_b = LibModelFox::ModelFoxStringView.new
|
696
|
+
LibModelFox.modelfox_bag_of_words_feature_contribution_get_column_name_b(c_bag_of_words_cosine_similarity_feature_contribution, c_column_name_b)
|
697
|
+
column_name_b = c_column_name_b.into_string
|
698
|
+
c_feature_contribution_value = FFI::MemoryPointer.new(:float)
|
699
|
+
LibModelFox.modelfox_bag_of_words_cosine_similarity_feature_contribution_get_feature_contribution_value(c_bag_of_words_cosine_similarity_feature_contribution, c_feature_contribution_value)
|
700
|
+
feature_contribution_value = c_feature_contribution_value.read(:float)
|
701
|
+
c_feature_value = FFI::MemoryPointer.new(:float)
|
702
|
+
LibModelFox.modelfox_bag_of_words_cosine_similarity_feature_contribution_get_feature_value(c_bag_of_words_cosine_similarity_feature_contribution, c_feature_value)
|
703
|
+
feature_value = c_feature_value.read(:float)
|
704
|
+
BagOfWordsCosineSimilarityFeatureContribution.new(
|
705
|
+
column_name_a: column_name_a,
|
706
|
+
column_name_b: column_name_b,
|
707
|
+
feature_contribution_value: feature_contribution_value,
|
708
|
+
feature_value: feature_value
|
709
|
+
)
|
710
|
+
end
|
711
|
+
|
712
|
+
def get_word_embedding_feature_contribution(c_feature_contribution)
|
713
|
+
c_word_embedding_feature_contribution = FFI::MemoryPointer.new(:pointer)
|
714
|
+
LibModelFox.modelfox_feature_contribution_entry_as_word_embedding(
|
715
|
+
c_feature_contribution, c_word_embedding_feature_contribution
|
716
|
+
)
|
717
|
+
c_word_embedding_feature_contribution = c_word_embedding_feature_contribution.read_pointer
|
718
|
+
c_column_name = LibModelFox::ModelFoxStringView.new
|
719
|
+
LibModelFox.modelfox_word_embedding_feature_contribution_get_column_name(c_word_embedding_feature_contribution, c_column_name)
|
720
|
+
column_name = c_column_name.into_string
|
721
|
+
c_feature_contribution_value = FFI::MemoryPointer.new(:float)
|
722
|
+
LibModelFox.modelfox_word_embedding_feature_contribution_get_feature_contribution_value(c_word_embedding_feature_contribution, c_feature_contribution_value)
|
723
|
+
feature_contribution_value = c_feature_contribution_value.read(:float)
|
724
|
+
c_value_index = FFI::MemoryPointer.new(:int)
|
725
|
+
LibModelFox.modelfox_word_embedding_feature_contribution_get_value_index(c_word_embedding_feature_contribution, c_value_index)
|
726
|
+
value_index = c_value_index.read(:int)
|
727
|
+
WordEmbeddingFeatureContribution.new(
|
728
|
+
column_name: column_name,
|
729
|
+
value_index: value_index,
|
730
|
+
feature_contribution_value: feature_contribution_value
|
731
|
+
)
|
732
|
+
end
|
733
|
+
|
734
|
+
def get_ngram(ngram)
|
735
|
+
c_ngram_type = FFI::MemoryPointer.new(:int)
|
736
|
+
LibModelFox.modelfox_ngram_get_type(ngram, c_ngram_type)
|
737
|
+
case c_ngram_type.read(:int)
|
738
|
+
when LibModelFox::ModelFoxNGramType[:unigram]
|
739
|
+
get_unigram_ngram(ngram)
|
740
|
+
when LibModelFox::ModelFoxNGramType[:bigram]
|
741
|
+
get_bigram_ngram(ngram)
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
def get_unigram_ngram(ngram)
|
746
|
+
c_token = LibModelFox::ModelFoxStringView.new
|
747
|
+
LibModelFox.modelfox_unigram_get_token(ngram, c_token)
|
748
|
+
token = c_token.into_string
|
749
|
+
Unigram.new(
|
750
|
+
token: token
|
751
|
+
)
|
752
|
+
end
|
753
|
+
|
754
|
+
def get_bigram_ngram(ngram)
|
755
|
+
c_token_a = LibModelFox::ModelFoxStringView.new
|
756
|
+
c_token_b = LibModelFox::ModelFoxStringView.new
|
757
|
+
LibModelFox.modelfox_bigram_get_token_a(ngram, c_token_a)
|
758
|
+
LibModelFox.modelfox_bigram_get_token_b(ngram, c_token_b)
|
759
|
+
token_a = c_token_a.into_string
|
760
|
+
token_b = c_token_b.into_string
|
761
|
+
Bigram.new(
|
762
|
+
token_a: token_a,
|
763
|
+
token_b: token_b
|
764
|
+
)
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
module LibModelFox
|
769
|
+
cpu = RbConfig::CONFIG['host_cpu']
|
770
|
+
os = RbConfig::CONFIG['host_os']
|
771
|
+
if cpu == 'x86_64' && os =~ /linux/
|
772
|
+
library_path = 'libmodelfox/x86_64-unknown-linux-gnu/libmodelfox.so'
|
773
|
+
elsif cpu == 'aarch64' && os =~ /linux/
|
774
|
+
library_path = 'libmodelfox/aarch64-unknown-linux-gnu/libmodelfox.so'
|
775
|
+
elsif cpu == 'x86_64' && os =~ /darwin/
|
776
|
+
library_path = 'libmodelfox/x86_64-apple-darwin/libmodelfox.dylib'
|
777
|
+
elsif (cpu == 'arm' || cpu == 'arm64') && os =~ /darwin/
|
778
|
+
library_path = 'libmodelfox/aarch64-apple-darwin/libmodelfox.dylib'
|
779
|
+
elsif cpu == 'x86_64' && os =~ /mingw/
|
780
|
+
library_path = 'libmodelfox/x86_64-pc-windows-msvc/modelfox.dll'
|
781
|
+
else
|
782
|
+
raise 'ModelFox for Ruby does not yet support your combination of CPU architecture and operating system. Open an issue at https://github.com/modelfoxdotdev/modelfox/issues/new or email us at help@modelfox.dev to complain.'
|
783
|
+
end
|
784
|
+
extend FFI::Library
|
785
|
+
ffi_lib File.expand_path(library_path.to_s, __dir__)
|
786
|
+
|
787
|
+
class ModelFoxStringView < FFI::Struct
|
788
|
+
layout :ptr, :pointer,
|
789
|
+
:len, :int
|
790
|
+
def into_string
|
791
|
+
self[:ptr].read_string(self[:len]).force_encoding('utf-8')
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
ModelFoxTaskType = enum(
|
796
|
+
:regression,
|
797
|
+
:binary_classification,
|
798
|
+
:multiclass_classification
|
799
|
+
)
|
800
|
+
|
801
|
+
ModelFoxFeatureContributionEntryType = enum(
|
802
|
+
:identity,
|
803
|
+
:normalized,
|
804
|
+
:one_hot_encoded,
|
805
|
+
:bag_of_words,
|
806
|
+
:bag_of_words_cosine_similarity,
|
807
|
+
:word_embedding
|
808
|
+
)
|
809
|
+
|
810
|
+
ModelFoxNGramType = enum(
|
811
|
+
:unigram,
|
812
|
+
:bigram
|
813
|
+
)
|
814
|
+
|
815
|
+
typedef :pointer, :modelfox_error
|
816
|
+
|
817
|
+
attach_function :modelfox_error_get_message, [:pointer, ModelFoxStringView.by_ref], :void
|
818
|
+
attach_function :modelfox_error_delete, [:pointer], :void
|
819
|
+
attach_function :modelfox_version, [ModelFoxStringView.by_ref], :void
|
820
|
+
attach_function :modelfox_model_from_bytes, [:pointer, :int, :pointer], :modelfox_error
|
821
|
+
attach_function :modelfox_model_from_path, [:string, :pointer], :modelfox_error
|
822
|
+
attach_function :modelfox_model_delete, [:pointer], :void
|
823
|
+
attach_function :modelfox_model_get_id, [:pointer, ModelFoxStringView.by_ref], :void
|
824
|
+
attach_function :modelfox_model_get_task, [:pointer, :pointer], :void
|
825
|
+
attach_function :modelfox_predict_input_new, [:pointer], :void
|
826
|
+
attach_function :modelfox_predict_input_delete, [:pointer], :void
|
827
|
+
attach_function :modelfox_predict_input_set_value_number, [:pointer, :string, :double], :int
|
828
|
+
attach_function :modelfox_predict_input_set_value_string, [:pointer, :string, :string], :int
|
829
|
+
attach_function :modelfox_predict_input_vec_new, [:pointer], :void
|
830
|
+
attach_function :modelfox_predict_input_vec_delete, [:pointer], :void
|
831
|
+
attach_function :modelfox_predict_input_vec_push, [:pointer, :pointer], :void
|
832
|
+
attach_function :modelfox_predict_options_new, [:pointer], :void
|
833
|
+
attach_function :modelfox_predict_options_delete, [:pointer], :void
|
834
|
+
attach_function :modelfox_predict_options_set_threshold, [:pointer, :float], :void
|
835
|
+
attach_function :modelfox_predict_options_set_compute_feature_contributions, [:pointer, :bool], :void
|
836
|
+
attach_function :modelfox_model_predict, [:pointer, :pointer, :pointer, :pointer], :modelfox_error
|
837
|
+
attach_function :modelfox_predict_output_delete, [:pointer], :void
|
838
|
+
attach_function :modelfox_predict_output_vec_delete, [:pointer], :void
|
839
|
+
attach_function :modelfox_predict_output_vec_len, [:pointer, :pointer], :void
|
840
|
+
attach_function :modelfox_predict_output_vec_get_at_index, [:pointer, :int, :pointer], :void
|
841
|
+
attach_function :modelfox_predict_output_as_regression, [:pointer, :pointer], :void
|
842
|
+
attach_function :modelfox_predict_output_as_binary_classification, [:pointer, :pointer], :void
|
843
|
+
attach_function :modelfox_predict_output_as_multiclass_classification, [:pointer, :pointer], :void
|
844
|
+
attach_function :modelfox_regression_predict_output_get_value, [:pointer, :pointer], :void
|
845
|
+
attach_function :modelfox_regression_predict_output_get_feature_contributions, [:pointer, :pointer], :void
|
846
|
+
attach_function :modelfox_binary_classification_predict_output_get_class_name, [:pointer, ModelFoxStringView.by_ref], :void
|
847
|
+
attach_function :modelfox_binary_classification_predict_output_get_probability, [:pointer, :pointer], :void
|
848
|
+
attach_function :modelfox_binary_classification_predict_output_get_feature_contributions, [:pointer, :pointer], :void
|
849
|
+
attach_function :modelfox_multiclass_classification_predict_output_get_class_name, [:pointer, ModelFoxStringView.by_ref], :void
|
850
|
+
attach_function :modelfox_multiclass_classification_predict_output_get_probability, [:pointer, :pointer], :void
|
851
|
+
attach_function :modelfox_multiclass_classification_predict_output_get_probabilities_len, [:pointer, :pointer], :void
|
852
|
+
attach_function :modelfox_multiclass_classification_predict_output_probabilities_iter_delete, [:pointer], :void
|
853
|
+
attach_function :modelfox_multiclass_classification_predict_output_get_probabilities_iter, [:pointer, :pointer], :void
|
854
|
+
attach_function :modelfox_multiclass_classification_predict_output_probabilities_iter_next, [:pointer, :pointer, :pointer], :bool
|
855
|
+
attach_function :modelfox_multiclass_classification_predict_output_feature_contributions_iter_delete, [:pointer], :void
|
856
|
+
attach_function :modelfox_multiclass_classification_predict_output_get_feature_contributions_iter, [:pointer, :pointer], :void
|
857
|
+
attach_function :modelfox_multiclass_classification_predict_output_feature_contributions_iter_next, [:pointer, :pointer, :pointer], :bool
|
858
|
+
attach_function :modelfox_feature_contributions_get_baseline_value, [:pointer, :pointer], :void
|
859
|
+
attach_function :modelfox_feature_contributions_get_output_value, [:pointer, :pointer], :void
|
860
|
+
attach_function :modelfox_feature_contributions_get_entries_len, [:pointer, :pointer], :void
|
861
|
+
attach_function :modelfox_feature_contributions_get_entry_at_index, [:pointer, :int, :pointer], :void
|
862
|
+
attach_function :modelfox_feature_contribution_entry_get_type, [:pointer, :pointer], :void
|
863
|
+
attach_function :modelfox_feature_contribution_entry_as_identity, [:pointer, :pointer], :void
|
864
|
+
attach_function :modelfox_feature_contribution_entry_as_normalized, [:pointer, :pointer], :void
|
865
|
+
attach_function :modelfox_feature_contribution_entry_as_one_hot_encoded, [:pointer, :pointer], :void
|
866
|
+
attach_function :modelfox_feature_contribution_entry_as_bag_of_words, [:pointer, :pointer], :void
|
867
|
+
attach_function :modelfox_feature_contribution_entry_as_bag_of_words_cosine_similarity, [:pointer, :pointer], :void
|
868
|
+
attach_function :modelfox_feature_contribution_entry_as_word_embedding, [:pointer, :pointer], :void
|
869
|
+
attach_function :modelfox_identity_feature_contribution_get_column_name, [:pointer, ModelFoxStringView.by_ref], :void
|
870
|
+
attach_function :modelfox_identity_feature_contribution_get_feature_value, [:pointer, :pointer], :void
|
871
|
+
attach_function :modelfox_identity_feature_contribution_get_feature_contribution_value, [:pointer, :pointer], :void
|
872
|
+
attach_function :modelfox_normalized_feature_contribution_get_column_name, [:pointer, ModelFoxStringView.by_ref], :void
|
873
|
+
attach_function :modelfox_normalized_feature_contribution_get_feature_value, [:pointer, :pointer], :void
|
874
|
+
attach_function :modelfox_normalized_feature_contribution_get_feature_contribution_value, [:pointer, :pointer], :void
|
875
|
+
attach_function :modelfox_one_hot_encoded_feature_contribution_get_column_name, [:pointer, ModelFoxStringView.by_ref], :void
|
876
|
+
attach_function :modelfox_one_hot_encoded_feature_contribution_get_variant, [:pointer, ModelFoxStringView.by_ref], :void
|
877
|
+
attach_function :modelfox_one_hot_encoded_feature_contribution_get_feature_value, [:pointer, :pointer], :void
|
878
|
+
attach_function :modelfox_one_hot_encoded_feature_contribution_get_feature_contribution_value, [:pointer, :pointer], :void
|
879
|
+
attach_function :modelfox_bag_of_words_feature_contribution_get_column_name, [:pointer, ModelFoxStringView.by_ref], :void
|
880
|
+
attach_function :modelfox_bag_of_words_feature_contribution_get_feature_value, [:pointer, :pointer], :void
|
881
|
+
attach_function :modelfox_bag_of_words_feature_contribution_get_feature_contribution_value, [:pointer, :pointer], :void
|
882
|
+
attach_function :modelfox_bag_of_words_feature_contribution_get_ngram, [:pointer, :pointer], :void
|
883
|
+
attach_function :modelfox_ngram_get_type, [:pointer, :pointer], :void
|
884
|
+
attach_function :modelfox_unigram_get_token, [:pointer, ModelFoxStringView.by_ref], :void
|
885
|
+
attach_function :modelfox_bigram_get_token_a, [:pointer, ModelFoxStringView.by_ref], :void
|
886
|
+
attach_function :modelfox_bigram_get_token_b, [:pointer, ModelFoxStringView.by_ref], :void
|
887
|
+
attach_function :modelfox_bag_of_words_cosine_similarity_feature_contribution_get_column_name_a, [:pointer, ModelFoxStringView.by_ref], :void
|
888
|
+
attach_function :modelfox_bag_of_words_cosine_similarity_feature_contribution_get_column_name_b, [:pointer, ModelFoxStringView.by_ref], :void
|
889
|
+
attach_function :modelfox_bag_of_words_cosine_similarity_feature_contribution_get_feature_value, [:pointer, :pointer], :void
|
890
|
+
attach_function :modelfox_bag_of_words_cosine_similarity_feature_contribution_get_feature_contribution_value, [:pointer, :pointer], :void
|
891
|
+
attach_function :modelfox_word_embedding_feature_contribution_get_column_name, [:pointer, ModelFoxStringView.by_ref], :void
|
892
|
+
attach_function :modelfox_word_embedding_feature_contribution_get_value_index, [:pointer, :pointer], :void
|
893
|
+
attach_function :modelfox_word_embedding_feature_contribution_get_feature_contribution_value, [:pointer, :pointer], :void
|
894
|
+
end
|
895
|
+
end
|