Prenons ces données
> allt <- data.frame(day = rep(c("mon", "tue", "wed"), each =3), id = c(1:3,2:4,3:5))
> allt
day id
1 mon 1
2 mon 2
3 mon 3
4 tue 2
5 tue 3
6 tue 4
7 wed 3
8 wed 4
9 wed 5
Dans la trame de données finale, nous pouvons voir que pour le jour "mon" nous avons des identifiants [1,2,3] et pour "mar" nous avons [ 2,3,4]. Donc, si nous faisons l'intersection de ces vecteurs, nous obtenons [2,3] et si nous faisons l'union, nous obtenons [1,2,3,4]. Les longueurs de ces vecteurs sont de 2 respectivement 4 et le rapport est de 0,5. C'est le chiffre que je veux obtenir.
Je cherche donc un moyen généralisé d'obtenir ce rapport sur plus de catégories pour toutes les combinaisons possibles.
Le résultat pourrait être dans un format quelque chose comme une matrice de corrélation. Juste pour être clair, je suis intéressé par les intersections et l'union de 2 catégories, donc par exemple, je n'ai pas besoin d'une intersection à 4 voies (lun, mar, mer, jeu) - juste chaque intersection de 2 jours.
4 Réponses :
Peut-être quelque chose comme ça?
days <- levels(allt$day)
f <- function(x, y) {
xids <- allt$id[allt$day == x]
yids <- allt$id[allt$day == y]
length(intersect(xids, yids)) / length(union(xids, yids))
}
f <- Vectorize(f)
outer(days, days, f)
# [,1] [,2] [,3]
# [1,] 1.0 0.5 0.2
# [2,] 0.5 1.0 0.5
# [3,] 0.2 0.5 1.0
éventuellement canaliser cela dans set_colnames (days) et set_rownames(days)
Que fait le "Vectorize"?
Le f non vectorisé ne fonctionne pas correctement sur les vecteurs qui lui sont fournis (les fonctions à l'intérieur peuvent également prendre des vecteurs, f ne fait que passer le vecteur). Vectorize encapsule essentiellement la fonction dans sapply pour chaque élément de x et y appliquant des règles de recyclage et de telle sorte que chaque invocation soit appelée avec des arguments scalaires.
Ceci devrait faire l'affaire, et vous pouvez également faire plus de combinaisons mais en changeant la valeur de la fonction combn.
# Creating your dataset
monday<-data.frame(day=rep("mon",3),id=c(1:3))
tuesday<-data.frame(day=rep("tue",3),id=c(2:4))
saturday<-data.frame(day=rep("sat",3),id=c(3:5))
allt<-rbind(monday,tuesday,saturday)
# Creating a list of values pr day
library(dplyr)
aggregated_form <- allt %>%
group_by(day) %>%
summarise(ids = list(id))
# Function takes a list with two vectors and make intersect/join
intersecter <- function(list_of_lists) {
vec1 <- unlist(list_of_lists[1])
vec2 <- unlist(list_of_lists[2])
my_intersect <- intersect(vec1, vec2)
my_union <- union(vec1, vec2)
ratio <- length(my_intersect)/length(my_union)
return(ratio)
}
# Creates strings with all combinations
combination <- sapply(combn(aggregated_form$day,2, simplify = FALSE), paste, collapse = "-")
# Calculates you value for all combinations
values <- combn(aggregated_form$ids, 2, FUN = intersecter)
# Generates a dataframe with results
results <- data.frame(comb = combination,
value = values)
results
comb value
1 mon-tue 0.5
2 mon-sat 0.2
3 tue-sat 0.5
lapply(combn(unique(allt$day), 2, ,F), paste, collapse = "-") [[1]] [1] "mon-tue" [[2]] [1] "mon-sat" [[3]] [1] "tue-sat"
Je ne le suis pas, pas besoin d'être impoli. Vous pourriez dire que nous avons adopté une approche comparable (même si cela pourrait être discuté également), mais je n'ai même pas vu votre message avant de publier le mien.
Ou s'agit-il simplement de créer les «noms de combinaisons de jours»? Oui, je vois maintenant que cette seule ligne est presque la même, mais pas de soucis, j'ai copié-collé votre réponse. Parfois, les grands esprits se ressemblent;)
Vous ne pouvez pas épeler grand sans 8: - |
commencez par créer une matrice pour les résultats des intersections:
int/un
mon tue sat
mon 1.0 0.5 0.2
tue 0.5 1.0 0.5
sat 0.2 0.5 1.0
répliquer la matrice pour les unions:
for(col in colnames(int)){
for(row in colnames(int)){
int[row,col]<-length(intersect(allt[allt$day==col,"id"],allt[allt$day==row,"id"]))
un[row,col]<-length(union(allt[allt$day==col,"id"],allt[allt$day==row,"id"]))
}
}
calculer les intersections et les unions: p>
un<-int
Ensuite, il vous suffit de diviser les deux matrices:
int<-mat.or.vec(nr=length(unique(allt$day)),nc=length(unique(allt$day))) colnames(int)<-unique(allt$day) rownames(int)<-unique(allt$day)
Quel serait votre résultat attendu pour l'exemple donné?