#r #count
#r #подсчет
Вопрос:
Согласно следующей таблице, у меня много разных учителей (10,11,12, …) с разными идеями (1,2, … например, 1: Очень хорошо, 2: Хорошо, …) каждого класса (1,2,3, …). Некоторые учителя не имеют никакого представления о некоторых классах.
class Teacher-code Opinion
1 12 1
1 13 1
1 14 1
2 11 3
2 13 1
3 10 1
3 11 2
3 12 1
3 13 1
Это образец моей таблицы, но у меня много записей. Я хочу иметь симметричную матрицу учителей с подсчетами их одинаковых представлений о классах. например, учитель 12 и 13 имеют одинаковую идею в классе 1 и 3, тогда их элементы пересечения равны 2. Или коды учителей 14 и 13 имеют только одну и ту же идею о первом классе. Я хочу получить следующую матрицу:
[10] [11] [12] [13] [14]
[10] 0 0 1 1 0
[11] 0 0 0 0 0
[12] 1 0 0 2 1
[13] 1 0 2 0 1
[14] 0 0 1 1 0
Ответ №1:
Это базовое решение R, основанное на общем подходе, используемом для поиска общих строк между фреймами данных. Возможно, это может быть полезно.
Создайте функцию, которая найдет совпадение в вашем фрейме данных между преподавателями, которые разделяют другие общие значения в определенных столбцах (в данном случае, class
и Opinion
). С merge
помощью вы можете определить перекрытие и nrow
подсчитать перекрывающиеся строки.
С помощью outer
вы можете сгенерировать матрицу всех учителей. Функция, переданная продукту, должна быть векторизована.
the_teachers <- sort(unique(df$Teacher_code))
get_num_classes <- function(x, y) {
nrow(
merge(
df[df$Teacher_code == x, c("class", "Opinion")],
df[df$Teacher_code == y, c("class", "Opinion")]
)
)
}
mat <- outer(the_teachers, the_teachers, Vectorize(get_num_classes))
diag(mat) <- 0
dimnames(mat) <- list(the_teachers, the_teachers)
mat
Вывод
10 11 12 13 14
10 0 0 1 1 0
11 0 0 0 0 0
12 1 0 0 2 1
13 1 0 2 0 1
14 0 0 1 1 0
Редактировать: основываясь на комментарии, есть интерес к определению доли (пары учителей, разделяющих одинаковые мнения в одном классе) / (пары учителей, разделяющие один и тот же класс). Основываясь на той же логике, вы можете изменить функцию, как показано ниже. Отдельное слияние определит количество учителей, совместно использующих один и тот же класс. Если это число не равно нулю, оно будет определять количество мнений, разделяемых парой учителей. Если нет общих классов, функция просто вернет ноль. В зависимости от размера данных и согласованности между преподавателями это может быть оптимизировано дополнительно.
get_num_classes <- function(x, y) {
same_class <- nrow(
merge(
df[df$Teacher_code == x, "class", drop = F],
df[df$Teacher_code == y, "class", drop = F]
)
)
if (same_class != 0) {
same_opinion <- nrow(
merge(
df[df$Teacher_code == x, c("class", "Opinion")],
df[df$Teacher_code == y, c("class", "Opinion")]
)
)
return(same_opinion / same_class)
} else {
return(0)
}
}
Комментарии:
1. Блестящее решение с использованием
merge
. Поддержал ваш отличный ответ!2. Большое спасибо, ваши коды дают наилучший результат. У меня есть еще один вопрос. Если я хочу иметь эту долю в матрице: количество соглашений между двумя учителями (ваши коды) / количество классов, в которых два учителя высказали свое мнение, что я должен добавить к вашим кодам? например, 12, 13 имеют одинаковое мнение в двух классах (числитель), и они оба вносят свой вклад в 2 класса одновременно (знаменатель), тогда мы имеем 2/2 = 1 в матрице.
3. @SA12 Смотрите Отредактированный ответ — дайте мне знать, если это то, что вы имели в виду. Рад, что это было полезно!
4. Отлично! Я искренне ценю вашу помощь и содействие. @Ben
Ответ №2:
Вот базовый параметр R, определяющий пользовательскую функцию f
, где aggregate
pmin
vecsets::vintersect
применяются:
library(vecsets)
f <- function(df) {
u <- aggregate(. ~ Teacher_code, df, I)
res <- do.call(
pmin,
lapply(
u[c("class", "Opinion")],
function(x) outer(x, x, FUN = function(...) lengths(Vectorize(vintersect)(...)))
)
)
`dimnames<-`(`diag<-`(res, 0), rep(list(u[["Teacher_code"]]), 2))
}
и вы увидите
> f(df)
10 11 12 13 14
10 0 0 1 1 0
11 0 0 0 0 0
12 1 0 0 2 1
13 1 0 2 0 1
14 0 0 1 1 0
Комментарии:
1. К сожалению, вывод неточен в больших данных. Но спасибо за ваше внимание.
Ответ №3:
Я имею в виду, что это довольно отвратительный код (я уверен, что кто-то может сделать что-то лучше), но я думаю, что он дает вам нужный результат (это не домашнее задание, не так ли -.- ?). Также в будущем это упростит жизнь, если вы предоставите данные с помощью dput()
library(dplyr)
library(tidyr)
dat <- tibble(
class = c( 1,1,1,2,2,3,3,3,3),
Teacher_code = c(12,13,14,11,13,10,11,12,13),
Opinion = c(1,1,1,3,1,1,2,1,1)
)
dat2 <- complete(dat, class, Teacher_code)
classes <- unique(dat2$class)
teachers <- unique(dat2$Teacher_code)
len_teachers <- length(teachers)
mat <- matrix(nrow = len_teachers, ncol = len_teachers)
for(i in seq_along(teachers)){
for( j in seq_along(teachers)){
same_opinion <- 0
for(k in classes){
opinion_i <- dat2 %>% filter(Teacher_code == teachers[[i]] , class == k) %>% pull(Opinion)
opinion_j <- dat2 %>% filter(Teacher_code == teachers[[j]] , class == k) %>% pull(Opinion)
same_opinion <- same_opinion (opinion_i == opinion_j amp; !(is.na(opinion_i) | is.na(opinion_j)))
}
mat[i,j] <- same_opinion
}
}
Комментарии:
1. Я не могу получить соответствующий результат по вашим кодам, но спасибо за ваше внимание. Нет, это не домашнее задание, это исследование.