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 +7 -0
- data/ext/Rakefile +7 -0
- data/ext/krippendorff_alpha.c +109 -0
- data/ext/mkrf_conf.rb +1 -0
- data/ext/x86_64-darwin/krippendorff_alpha.o +0 -0
- data/ext/x86_64-darwin/libkrippendorff_alpha.bundle +0 -0
- data/krippendorff_alpha.gemspec +20 -0
- data/lib/krippendorff_alpha.rb +65 -0
- metadata +94 -0
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,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` }
|
Binary file
|
Binary file
|
@@ -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: []
|