krippendorff_alpha 0.0.2

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: 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: []