krippendorff_alpha 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac1085af7a90a35a6c158b0b40a5785b4c801b24
4
+ data.tar.gz: db5562b2b1731fddb1a773b35bb3d66c9bce319f
5
+ SHA512:
6
+ metadata.gz: 2a3c4ee44f8b3873f048d828ffdfbed80172693de54813c4544c2d5562320b7e6b2be71f1f62a9b5d4da882daa6a678f07de116e0308d1c3ea2b2e3b5450b345
7
+ data.tar.gz: 7532060d8915c324de3251a960cd34be828c2b16ca14673beffec0f4ebc161c26f6ec9c630a0a24dc1b5f59dbc858e3a37de87634df107a987be505c84da273e
data/ext/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'ffi-compiler/compile_task'
2
+
3
+ FFI::Compiler::CompileTask.new('krippendorff_alpha') do |c|
4
+ %w(stddef stdlib stdbool math assert).each do |fname|
5
+ c.have_header?("#{fname}.h", '/usr/include')
6
+ end
7
+ end
@@ -0,0 +1,109 @@
1
+ #include <stddef.h>
2
+ #include <stdlib.h>
3
+ #include <stdbool.h>
4
+ #include <math.h>
5
+ #include <assert.h>
6
+
7
+ bool _skip_flag(int index, int *skip_indexes, size_t skip_indexes_size)
8
+ {
9
+ for (size_t s_i = 0; s_i < skip_indexes_size; s_i++) {
10
+ if (skip_indexes[s_i] == index) {
11
+ return true;
12
+ }
13
+ }
14
+
15
+ return false;
16
+ }
17
+
18
+ double _metric(double c, double k)
19
+ {
20
+ return pow(c - k, 2);
21
+ }
22
+
23
+ double _krippendorff_alpha(double *in_array, size_t n_rows, size_t n_columns, int *skip_indexes, size_t skip_indexes_size, double *unique_values, size_t unique_values_size)
24
+ {
25
+ // Construct value-by-unit matrix
26
+ unsigned int *vu = calloc(n_columns * unique_values_size, sizeof(unsigned int));
27
+ assert(vu != NULL);
28
+
29
+ unsigned int *unit_totals = calloc(n_columns, sizeof(unsigned int));
30
+ assert(unit_totals != NULL);
31
+
32
+ unsigned int *unique_value_totals = calloc(unique_values_size, sizeof(unsigned int));
33
+ assert(unique_value_totals != NULL);
34
+
35
+ // Count the number of times the value occurs for each unit, accumulating overall totals as well
36
+ for (size_t v_i = 0; v_i < unique_values_size; v_i++) {
37
+ for (size_t u_i = 0; u_i < n_columns; u_i++) {
38
+ for (size_t r_i = 0; r_i < n_rows; r_i++) {
39
+ size_t flat_i = (u_i * n_rows) + r_i;
40
+
41
+ // Check if we match the unique value we're currently comparing against and tabulate,
42
+ // and skip over any values marked to be skipped
43
+ if (!_skip_flag(flat_i, skip_indexes, skip_indexes_size) &&
44
+ in_array[flat_i] == unique_values[v_i]) {
45
+ vu[(v_i * n_columns) + u_i] += 1;
46
+ unit_totals[u_i] += 1;
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ unsigned int total_pairable_values = 0;
53
+
54
+ // Calculate the marginal sums, now that we know if there are any lone values
55
+ for (size_t v_i = 0; v_i < unique_values_size; v_i++) {
56
+ for (size_t u_i = 0; u_i < n_columns; u_i++) {
57
+ // Skip any units with lone values
58
+ if (unit_totals[u_i] > 1) {
59
+ unique_value_totals[v_i] += vu[(v_i * n_columns) + u_i];
60
+ }
61
+ }
62
+
63
+ total_pairable_values += unique_value_totals[v_i];
64
+ }
65
+
66
+ // Calculate the observed disagreement
67
+ double d_o = 0.0;
68
+ for (size_t u_i = 0; u_i < n_columns; u_i++) {
69
+
70
+ double denominator = unit_totals[u_i] - 1;
71
+ if (denominator > 0) {
72
+
73
+ double sum_diff = 0.0;
74
+ for (size_t c_i = 0; c_i < unique_values_size; c_i++) {
75
+ for (size_t k_i = c_i + 1; k_i < unique_values_size; k_i++) {
76
+ double c = unique_values[c_i];
77
+ double k = unique_values[k_i];
78
+ double n_uc = vu[(c_i * n_columns) + u_i];
79
+ double n_uk = vu[(k_i * n_columns) + u_i];
80
+
81
+ sum_diff += n_uc * n_uk * _metric(c, k);
82
+ }
83
+ }
84
+
85
+ d_o += sum_diff / denominator;
86
+ }
87
+ }
88
+
89
+ // Calculate the expected disagreement
90
+ double d_e = 0.0;
91
+ for (size_t c_i = 0; c_i < unique_values_size; c_i++) {
92
+ for (size_t k_i = c_i + 1; k_i < unique_values_size; k_i++) {
93
+ double c = unique_values[c_i];
94
+ double k = unique_values[k_i];
95
+ double dot_c = unique_value_totals[c_i];
96
+ double dot_k = unique_value_totals[k_i];
97
+
98
+ d_e += dot_c * dot_k * _metric(c, k);
99
+ }
100
+ }
101
+
102
+ double a = 1 - (total_pairable_values - 1) * (d_o / d_e);
103
+
104
+ free(vu);
105
+ free(unit_totals);
106
+ free(unique_value_totals);
107
+
108
+ return a;
109
+ }
data/ext/mkrf_conf.rb ADDED
@@ -0,0 +1 @@
1
+ task :default { `make` }
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'krippendorff_alpha'
3
+ s.version = '0.0.2'
4
+ s.date = '2017-08-30'
5
+ s.summary = "Krippendorff Alpha implementation"
6
+ s.description = "A Krippendorff Alpha implementation for std-ruby Matrix library"
7
+ s.authors = ["Brad Folkens"]
8
+ s.email = 'bfolkens@gmail.com'
9
+ s.files = %w(krippendorff_alpha.gemspec) + Dir.glob("{lib,spec,ext}/**/*")
10
+ s.license = 'MIT'
11
+ s.homepage = 'http://github.com/bfolkens/ruby-krippendorff-alpha'
12
+
13
+ s.extensions << 'ext/Rakefile'
14
+ s.extensions << 'ext/mkrf_conf.rb'
15
+
16
+ s.add_development_dependency 'minitest', '~> 0'
17
+ s.add_development_dependency 'rake', '~> 0'
18
+
19
+ s.add_dependency 'ffi-compiler', '~> 1.0'
20
+ end
@@ -0,0 +1,65 @@
1
+ require 'matrix'
2
+ require 'ffi'
3
+ require 'ffi-compiler/loader'
4
+
5
+ module KrippendorffAlphaLib
6
+ extend FFI::Library
7
+
8
+ ffi_lib FFI::Library::LIBC
9
+
10
+ # memory allocators
11
+ attach_function :malloc, [:size_t], :pointer
12
+ attach_function :calloc, [:size_t], :pointer
13
+ attach_function :valloc, [:size_t], :pointer
14
+ attach_function :realloc, [:pointer, :size_t], :pointer
15
+ attach_function :free, [:pointer], :void
16
+
17
+ # memory movers
18
+ attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
19
+ attach_function :bcopy, [:pointer, :pointer, :size_t], :void
20
+
21
+ ffi_lib FFI::Compiler::Loader.find('krippendorff_alpha')
22
+ attach_function :_krippendorff_alpha, [:pointer, :size_t, :size_t, :pointer, :size_t, :pointer, :size_t], :double
23
+ end
24
+
25
+ module KrippendorffAlpha
26
+ include KrippendorffAlphaLib
27
+
28
+ # Calculate Krippendorff's alpha (inter-rater reliability)
29
+ # http://repository.upenn.edu/cgi/viewcontent.cgi?article=1043&context=asc_papers
30
+ #
31
+ # Assumed input (Matrix)
32
+ # [
33
+ # [ nil, nil, nil, nil, nil, 3, 4, 1, 2, 1, 1, 3, 3, nil, 3 ], # coder 1
34
+ # [ 1, nil, 2, 1, 3, 3, 4, 3, nil, nil, nil, nil, nil, nil, nil], # coder 2
35
+ # [ nil, nil, 2, 1, 3, 4, 4, nil, 2, 1, 1, 3, 3, nil, 4 ] # coder 3
36
+ # ]
37
+ def krippendorff_alpha
38
+ in_array = self.to_a
39
+ in_array_flattened = in_array.transpose.flatten
40
+ unique_values = in_array.flatten.compact.uniq
41
+
42
+ # We need to keep track of the skip indexes separately since we can't send nils via C array of double
43
+ skip_indexes = []
44
+ in_array_flattened.each_with_index do |element, i|
45
+ skip_indexes << i if element.nil?
46
+ end
47
+
48
+ # Reformat the in_array to not have nil
49
+ skip_indexes.each {|i| in_array_flattened[i] = 0 }
50
+
51
+ FFI::MemoryPointer.new(:double, in_array_flattened.size) do |in_array_ptr|
52
+ FFI::MemoryPointer.new(:double, unique_values.size) do |unique_values_ptr|
53
+ FFI::MemoryPointer.new(:int, skip_indexes.size) do |skip_indexes_ptr|
54
+ in_array_ptr.write_array_of_double(in_array_flattened)
55
+ unique_values_ptr.write_array_of_double(unique_values)
56
+ skip_indexes_ptr.write_array_of_int(skip_indexes)
57
+
58
+ return _krippendorff_alpha(in_array_ptr, row_count, column_count, skip_indexes_ptr, skip_indexes.size, unique_values_ptr, unique_values.size)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ Matrix.send(:include, KrippendorffAlpha)
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: krippendorff_alpha
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Brad Folkens
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ffi-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ description: A Krippendorff Alpha implementation for std-ruby Matrix library
56
+ email: bfolkens@gmail.com
57
+ executables: []
58
+ extensions:
59
+ - ext/Rakefile
60
+ - ext/mkrf_conf.rb
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ext/Rakefile
64
+ - ext/krippendorff_alpha.c
65
+ - ext/mkrf_conf.rb
66
+ - ext/x86_64-darwin/krippendorff_alpha.o
67
+ - ext/x86_64-darwin/libkrippendorff_alpha.bundle
68
+ - krippendorff_alpha.gemspec
69
+ - lib/krippendorff_alpha.rb
70
+ homepage: http://github.com/bfolkens/ruby-krippendorff-alpha
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.4.8
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Krippendorff Alpha implementation
94
+ test_files: []