Your question can be seen as a mix of two different questions. First one is how to calculate agreement in case of multi-label annotation. The second one is what function to use, in R or in a different language, to do this calculation.
- How to calculate agreement for multi-label annotation.
The answer to first question is that you should:
- How to calculate agreement for multi-label annotation in R or other language/tool
Here is explained how to calculate Krippendorff's alpha for multi-label annotation using MASI distance using Python.
Here is a working example with a part of your data:
import nltk
from nltk.metrics import agreement
from nltk.metrics.agreement import AnnotationTask
from nltk.metrics import masi_distance
task_data = [('coder1','Item0',frozenset(['l1','l2'])),
('coder2','Item0',frozenset(['l1'])),
('coder1','Item1',frozenset(['l1','l2'])),
('coder2','Item1',frozenset(['l1','l2'])),
('coder1','Item2',frozenset(['l1'])),
('coder2','Item2',frozenset(['l1']))]
task = AnnotationTask(distance = masi_distance)
task.load_array(task_data)
task.alpha()
I have not found any implementation Krippendorff's alpha in R that lets you use custom distance function as nltk.metrics.agreement does.
The solution is to use irrCAC library, as it's krippen.alpha function accepts the weight matrix as argument. Than, one can calculate the weight matrix for all observed combination of labels using any distance function.
Here is my solution. I call python to calculate MASI distance.
library(irrCAC)
library(reticulate)
#creating the dataset as dataframe
dataset <- c("l1, l2",
"l1","l1, l2",
"l1, l2","l1",
"l1","l3","l3",
"l3","l1, l3","l4",
"l4","l2",
"l4","l1, l2",
"l1","l1, l2",
"l1, l2, l3",
"l1","l1",
"l1","l1")
dataset <- data.frame(matrix(dataset,ncol = 2, byrow = T), stringsAsFactors = F)
colnames(dataset) <- c("Coder1", "Coder2")
#function that calculates MASI distance using python nltk.metrics
pybuiltins <- import_builtins()
nltk <- import("nltk")
masi <- function(x,y,split = " ")
{
if(length(str_split(x,split,simplify = F)[[1]]) == 1)
{
x <- str_split(x,split,simplify = F)
}else
{
x <- unlist(str_split(x,split,simplify = F))
}
if(length(str_split(y,split,simplify = F)[[1]]) == 1)
{
y <- str_split(y,split,simplify = F)
}else
{
y <- unlist(str_split(y,split,simplify = F))
}
masiD <- nltk$masi_distance(pybuiltins$set(x),pybuiltins$set(y))
masiD
}
#calculating weight matrix for all observed combination of lables using MASI distance
labelsCombAll <- unique(unlist(dataset))
distMasi <- matrix(nrow = length(labelsCombAll),ncol = length(labelsCombAll),
dimnames = list(labelsCombAll,labelsCombAll))
for(i in 1:nrow(distMasi))
for(j in 1:ncol(distMasi))
{
distMasi[i,j] <- 1-masi(labelsCombAll[i],labelsCombAll[j],", ")
}
#calculating krippendorff alpha
krippen.alpha.raw(dataset, weights = distMasi,categ.labels = rownames(distMasi))
```