numo-libsvm 0.1.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: abc7fcd5ce86d8e2d0576290a8053b77f4e06d5e
4
+ data.tar.gz: f731f73a38b034e36f9b79164c5d0cc27ca30f1a
5
+ SHA512:
6
+ metadata.gz: 82c172d2cd872c3cae5bcbc685d175489401ca19b963af80aac4c8f380fefe40d2c54cb045d471ff1887a792063c694c222781cb1ca7d34082e45f3726d2d848
7
+ data.tar.gz: 6f483ae0c4c8ed902bfa75727dbeaa15559f5dca5c0903d624e93cc6a7239e635441394e9a325b752ac2b0e6894d149e3996e15c6d1e0a7935e08c3aed613a91
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /bin/
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
14
+
15
+ *.swp
16
+ *.bundle
17
+ mkmf.log
18
+ tags
19
+ .DS_Store
20
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ ---
2
+ sudo: true
3
+ os: linux
4
+ dist: bionic
5
+ language: ruby
6
+ cache: bundler
7
+ rvm:
8
+ - '2.4'
9
+ - '2.5'
10
+ - '2.6'
11
+
12
+ before_install:
13
+ - sudo apt-get install -y libsvm-dev
14
+ - gem install bundler -v 2.0.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ # 0.1.0
2
+ - First release.
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at yoshoku@outlook.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in numo-libsvm.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2019 Atsushi Tatsuma
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of the copyright holder nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # Numo::Libsvm
2
+
3
+ [![Build Status](https://travis-ci.org/yoshoku/numo-libsvm.svg?branch=master)](https://travis-ci.org/yoshoku/numo-libsvm)
4
+ [![Gem Version](https://badge.fury.io/rb/numo-libsvm.svg)](https://badge.fury.io/rb/numo-libsvm)
5
+ [![BSD 3-Clause License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://github.com/yoshoku/numo-libsvm/blob/master/LICENSE.txt)
6
+
7
+ Numo::Libsvm is a Ruby gem binding to the [LIBSVM](https://github.com/cjlin1/libsvm) library.
8
+ LIBSVM is one of the famous libraries that implemented Support Vector Machines,
9
+ and provides functions for support vector classifier, regression, and distribution estimation.
10
+ Numo::Libsvm makes to use the LIBSVM functions with dataset represented by [Numo::NArray](https://github.com/ruby-numo/numo-narray).
11
+
12
+ Note: There are other useful Ruby gems binding to LIBSVM:
13
+ [rb-libsvm](https://github.com/febeling/rb-libsvm) by C. Florian Ebeling,
14
+ [libsvm-ruby-swig](https://github.com/tomz/libsvm-ruby-swig) by Tom Zeng,
15
+ and [jrb-libsvm](https://github.com/andreaseger/jrb-libsvm) by Andreas Eger.
16
+
17
+ ## Installation
18
+ Numo::Libsvm does not bundle LIBSVM unlike rb-libsvm. You need to install LIBSVM in advance along your environment.
19
+
20
+ macOS:
21
+
22
+ $ brew install libsvm
23
+
24
+ Ubuntu:
25
+
26
+ $ sudo apt-get install libsvm-dev
27
+
28
+ Add this line to your application's Gemfile:
29
+
30
+ ```ruby
31
+ gem 'numo-libsvm'
32
+ ```
33
+
34
+ And then execute:
35
+
36
+ $ bundle
37
+
38
+ Or install it yourself as:
39
+
40
+ $ gem install numo-libsvm
41
+
42
+ ## Usage
43
+
44
+ ### Preparation
45
+
46
+ In the following examples, we use [red-datasets](https://github.com/red-data-tools/red-datasets) to download dataset.
47
+
48
+ $ gem install red-datasets-numo-narray
49
+
50
+ ### Example 1. Cross-validation
51
+
52
+ We conduct cross validation of support vector classifier on [Iris dataset](https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass.html#iris).
53
+
54
+ ```ruby
55
+ require 'numo/narray'
56
+ require 'numo/libsvm'
57
+ require 'datasets-numo-narray'
58
+
59
+ # Download Iris dataset.
60
+ puts 'Download dataset.'
61
+ iris = Datasets::LIBSVM.new('iris').to_narray
62
+ x = iris[true, 1..-1]
63
+ y = iris[true, 0]
64
+
65
+ # Define parameters of C-SVC with RBF Kernel.
66
+ param = {
67
+ svm_type: Numo::Libsvm::SvmType::C_SVC,
68
+ kernel_type: Numo::Libsvm::KernelType::RBF,
69
+ gamma: 1.0,
70
+ C: 1
71
+ }
72
+
73
+ # Perform 5-cross validation.
74
+ puts 'Perform cross validation.'
75
+ n_folds = 5
76
+ predicted = Numo::Libsvm.cv(x, y, param, n_folds)
77
+
78
+ # Print mean accuracy.
79
+ mean_accuracy = y.eq(predicted).count.fdiv(y.size)
80
+ puts "Accuracy: %.1f %%" % (100 * mean_accuracy)
81
+ ```
82
+
83
+ Execution result in the following:
84
+
85
+ ```sh
86
+ Download dataset.
87
+ Perform cross validation.
88
+ Accuracy: 96.0 %
89
+ ```
90
+
91
+ ### Example 2. Pendigits dataset classification
92
+
93
+ We first train the support vector classifier with RBF kernel using training [pendigits dataset](https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass.html#pendigits).
94
+
95
+ ```ruby
96
+ require 'numo/narray'
97
+ require 'numo/libsvm'
98
+ require 'datasets-numo-narray'
99
+
100
+ # Download pendigits training dataset.
101
+ puts 'Download dataset.'
102
+ pendigits = Datasets::LIBSVM.new('pendigits').to_narray
103
+ x = pendigits[true, 1..-1]
104
+ y = pendigits[true, 0]
105
+
106
+ # Define parameters of C-SVC with RBF Kernel.
107
+ param = {
108
+ svm_type: Numo::Libsvm::SvmType::C_SVC,
109
+ kernel_type: Numo::Libsvm::KernelType::RBF,
110
+ gamma: 0.0001,
111
+ C: 10,
112
+ shrinking: true
113
+ }
114
+
115
+ # Perform training procedure.
116
+ puts 'Train support vector machine.'
117
+ model = Numo::Libsvm.train(x, y, param)
118
+
119
+ # Save parameters and trained model.
120
+ puts 'Save parameters and model with Marshal.'
121
+ File.open('pendigits.dat', 'wb') { |f| f.write(Marshal.dump([param, model])) }
122
+ ```
123
+
124
+ ```sh
125
+ $ ruby train.rb
126
+ Download dataset.
127
+ Train support vector machine.
128
+ Save paramters and model with Marshal.
129
+ ```
130
+
131
+ We then predict labels of testing dataset, and evaluate the classifier.
132
+
133
+ ```ruby
134
+ require 'numo/narray'
135
+ require 'numo/libsvm'
136
+ require 'datasets-numo-narray'
137
+
138
+ # Download pendigits testing dataset.
139
+ puts 'Download dataset.'
140
+ pendigits_test = Datasets::LIBSVM.new('pendigits', note: 'testing').to_narray
141
+ x = pendigits_test[true, 1..-1]
142
+ y = pendigits_test[true, 0]
143
+
144
+ # Load parameter and model.
145
+ puts 'Load parameter and model.'
146
+ param, model = Marshal.load(File.binread('pendigits.dat'))
147
+
148
+ # Predict labels.
149
+ puts 'Predict labels.'
150
+ predicted = Numo::Libsvm.predict(x, param, model)
151
+
152
+ # Evaluate classification results.
153
+ mean_accuracy = y.eq(predicted).count.fdiv(y.size)
154
+ puts "Accuracy: %.1f %%" % (100 * mean_accuracy)
155
+ ```
156
+
157
+ ```sh
158
+ $ ruby test.rb
159
+ Download dataset.
160
+ Load parameter and model.
161
+ Predict labels.
162
+ Accuracy: 98.3 %
163
+ ```
164
+
165
+ ### Note
166
+ The hyperparameter of SVM is given with Ruby Hash on Numo::Libsvm.
167
+ The hash key of hyperparameter and its meaning match the struct svm_parameter of LIBSVM.
168
+ The svm_parameter is detailed in [LIBSVM README](https://github.com/cjlin1/libsvm/blob/master/README).
169
+
170
+ ## Contributing
171
+
172
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yoshoku/numo-libsvm. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
173
+
174
+ ## License
175
+
176
+ The gem is available as open source under the terms of the [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
177
+
178
+ ## Code of Conduct
179
+
180
+ Everyone interacting in the Numo::Libsvm project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/numo-libsvm/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require 'rake/extensiontask'
7
+
8
+ task :build => :compile
9
+
10
+ Rake::ExtensionTask.new('libsvmext') do |ext|
11
+ ext.ext_dir = 'ext/numo/libsvm'
12
+ ext.lib_dir = 'lib/numo/libsvm'
13
+ end
14
+
15
+ task :default => [:clobber, :compile, :spec]
@@ -0,0 +1,162 @@
1
+
2
+ #include "converter.h"
3
+
4
+ VALUE int_vec_to_nary(int* const arr, int const size)
5
+ {
6
+ int i;
7
+ size_t shape[1] = { size };
8
+ VALUE v = rb_narray_new(numo_cInt32, 1, shape);
9
+ int32_t* vp = (int32_t*)na_get_pointer_for_write(v);
10
+ for (i = 0; i < size; i++) { vp[i] = (int32_t)arr[i]; }
11
+ return v;
12
+ }
13
+
14
+ int* nary_to_int_vec(VALUE vec_val)
15
+ {
16
+ int i;
17
+ int n_elements;
18
+ narray_t* vec_nary;
19
+ int32_t* vec_pt;
20
+ int* vec;
21
+
22
+ if (vec_val == Qnil) return NULL;
23
+
24
+ GetNArray(vec_val, vec_nary);
25
+ n_elements = (int)NA_SHAPE(vec_nary)[0];
26
+
27
+ vec = ALLOC_N(int, n_elements);
28
+ vec_pt = (int32_t*)na_get_pointer_for_read(vec_val);
29
+ for (i = 0; i < n_elements; i++) { vec[i] = (int)vec_pt[i]; }
30
+
31
+ return vec;
32
+ }
33
+
34
+ VALUE dbl_vec_to_nary(double* const arr, int const size)
35
+ {
36
+ int i;
37
+ size_t shape[1] = { size };
38
+ VALUE v = rb_narray_new(numo_cDFloat, 1, shape);
39
+ double* vp = (double*)na_get_pointer_for_write(v);
40
+ for (i = 0; i < size; i++) { vp[i] = arr[i]; }
41
+ return v;
42
+ }
43
+
44
+ double* nary_to_dbl_vec(VALUE vec_val)
45
+ {
46
+ int n_elements;
47
+ narray_t* vec_nary;
48
+ double* vec_pt;
49
+ double* vec;
50
+
51
+ if (vec_val == Qnil) return NULL;
52
+
53
+ GetNArray(vec_val, vec_nary);
54
+ n_elements = (int)NA_SHAPE(vec_nary)[0];
55
+
56
+ vec = ALLOC_N(double, n_elements);
57
+ vec_pt = (double*)na_get_pointer_for_read(vec_val);
58
+ memcpy(vec, vec_pt, n_elements * sizeof(double));
59
+
60
+ return vec;
61
+ }
62
+
63
+ VALUE dbl_mat_to_nary(double** const mat, int const n_rows, int const n_cols)
64
+ {
65
+ int i, j;
66
+ size_t shape[2] = { n_rows, n_cols };
67
+ VALUE v = rb_narray_new(numo_cDFloat, 2, shape);
68
+ double* vp = (double*)na_get_pointer_for_write(v);
69
+
70
+ for (i = 0; i < n_rows; i++) {
71
+ for (j = 0; j < n_cols; j++) {
72
+ vp[i * n_cols + j] = mat[i][j];
73
+ }
74
+ }
75
+
76
+ return v;
77
+ }
78
+
79
+ double** nary_to_dbl_mat(VALUE mat_val)
80
+ {
81
+ int i, j;
82
+ int n_rows, n_cols;
83
+ narray_t* mat_nary;
84
+ double* mat_pt;
85
+ double** mat;
86
+
87
+ if (mat_val == Qnil) return NULL;
88
+
89
+ GetNArray(mat_val, mat_nary);
90
+ n_rows = (int)NA_SHAPE(mat_nary)[0];
91
+ n_cols = (int)NA_SHAPE(mat_nary)[1];
92
+
93
+ mat_pt = (double*)na_get_pointer_for_read(mat_val);
94
+ mat = ALLOC_N(double*, n_rows);
95
+ for (i = 0; i < n_rows; i++) {
96
+ mat[i] = ALLOC_N(double, n_cols);
97
+ for (j = 0; j < n_cols; j++) {
98
+ mat[i][j] = mat_pt[i * n_cols + j];
99
+ }
100
+ }
101
+
102
+ return mat;
103
+ }
104
+
105
+ VALUE svm_nodes_to_nary(struct svm_node** const support_vecs, const int n_support_vecs)
106
+ {
107
+ int i, j;
108
+ int n_dimensions = 0;
109
+ size_t shape[2] = { n_support_vecs, 1 };
110
+ VALUE v;
111
+ double* vp;
112
+
113
+ for (i = 0; i < n_support_vecs; i++) {
114
+ for (j = 0; support_vecs[i][j].index != -1; j++) {
115
+ if (n_dimensions < support_vecs[i][j].index) {
116
+ n_dimensions = support_vecs[i][j].index;
117
+ }
118
+ }
119
+ }
120
+
121
+ shape[1] = n_dimensions;
122
+ v = rb_narray_new(numo_cDFloat, 2, shape);
123
+ vp = (double*)na_get_pointer_for_write(v);
124
+ memset(vp, 0, n_support_vecs * n_dimensions * sizeof(double));
125
+
126
+ for (i = 0; i < n_support_vecs; i++) {
127
+ for (j = 0; support_vecs[i][j].index != -1; j++) {
128
+ vp[i * n_dimensions + support_vecs[i][j].index - 1] = support_vecs[i][j].value;
129
+ }
130
+ }
131
+
132
+ return v;
133
+ }
134
+
135
+ struct svm_node** nary_to_svm_nodes(VALUE model_val)
136
+ {
137
+ int i, j;
138
+ int n_rows, n_cols;
139
+ narray_t* model_nary;
140
+ double* model_pt;
141
+ struct svm_node** support_vecs;
142
+
143
+ if (model_val == Qnil) return NULL;
144
+
145
+ GetNArray(model_val, model_nary);
146
+ n_rows = (int)NA_SHAPE(model_nary)[0];
147
+ n_cols = (int)NA_SHAPE(model_nary)[1];
148
+
149
+ model_pt = (double*)na_get_pointer_for_read(model_val);
150
+ support_vecs = ALLOC_N(struct svm_node*, n_rows);
151
+ for (i = 0; i < n_rows; i++) {
152
+ support_vecs[i] = ALLOC_N(struct svm_node, n_cols + 1);
153
+ for (j = 0; j < n_cols; j++) {
154
+ support_vecs[i][j].index = j + 1;
155
+ support_vecs[i][j].value = model_pt[i * n_cols + j];
156
+ }
157
+ support_vecs[i][n_cols].index = -1;
158
+ support_vecs[i][n_cols].value = 0.0;
159
+ }
160
+
161
+ return support_vecs;
162
+ }