J'ai un doute assez spécifique, mais cela devrait être facile à résoudre, je ne peux pas penser comment ...
J'ai un simple bloc de données comme celui-ci:
Target hit.by.Shooters 1 1 2 1;2;3 3 2;3 4 NA 5 1 6 1;2 7 NA 8 2 9 1;2 10 1
Ce bloc de données m'indique les cibles (de 1 à 10) qui sont manquées par chaque Shooter .
Je voudrais obtenir un cadre de données différent qui me dit, par Target , quel Shooter \ s l'a créé.
Le résultat serait:
mydf <- data.frame(Shooter=1:3, Targets.missed=c(paste(sample(1:10,4),collapse=";"), paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";"))) mydf Shooter Targets.missed 1 1 3;8;4;7 2 2 10;1;5;7;4 3 3 5;9;4;10;8;1;6;7
3 Réponses :
Nous développons les données en divisant au Ou une autre option est et modifiez les noms des colonnes si nécessaire ; de la 'Targets.missed' en format 'long', puis regroupées par 'Shooter', résumer avec un liste des numéros qui ne sont pas dans la 'Targets.missed' à partir de 1:10, unnest la colonne list , regroupés par 'Target', résumez en collez les éléments uniques 'Shooter' en une seule chaîne, et remplissez les éléments manquants à partir de 1:10 avec NA en utilisant completemydf <- structure(list(Shooter = 1:3, Targets.missed = c("3;8;4;7", "10;1;5;7;4",
"5;9;4;10;8;1;6;7")), class = "data.frame", row.names = c("1",
"2", "3"))
base R en divisant le 'Targets.missed' (en supposant character class) dans une liste de vecteurs s, parcourez la liste , récupérez les valeurs qui ne sont pas dans 1:10 (avec setdiff ), définir les noms de la list avec la colonne 'Shooter', stack la clé / val list paires dans un data.frame à deux colonnes, récupère les lignes uniques , agrégat c ode> en coller la colonne 'ind' groupée par 'values', merge avec un ensemble de données 'values' complet de 1:10 names(out1) <- c('Target', 'hit.by.Shooters')
out <- aggregate(ind ~ values,
unique(stack(setNames(lapply(strsplit(mydf$Targets.missed, ';'),
setdiff, x= 1:10), mydf$Shooter))), FUN = paste, collapse=";")
out1 <- merge(data.frame(values = 1:10), out, all.x = TRUE)
data
library(tidyverse)
mydf %>%
separate_rows(Targets.missed) %>%
group_by(Shooter) %>%
summarise(Target = list(setdiff(1:10, Targets.missed))) %>%
unnest %>%
group_by(Target) %>%
summarise(hit.by.Shooters = paste(unique(Shooter), collapse=";")) %>%
complete(Target = 1:10)
# A tibble: 10 x 2
# Target hit.by.Shooters
# <int> <chr>
# 1 1 1
# 2 2 1;2;3
# 3 3 2;3
# 4 4 <NA>
# 5 5 1
# 6 6 1;2
# 7 7 <NA>
# 8 8 2
# 9 9 1;2
#10 10 1
data.table approche
library( data.table )
#vector with all possible targets
targets.v <- 1:10
#split the missed targets to a list
missed.list <- strsplit( mydf$Targets.missed, ";")
#inverse, to get all hit targets
hit.list <- lapply( missed.list, function(x) as.data.table( targets.v[!targets.v %in% x] ) )
#bind hit targets to data.table
dt <- rbindlist( hit.list, idcol = "shooter" )
#summarise (paste with collapse), and join on all possible targets
dt[, .(hit.by.shooters = paste(shooter, collapse = ";")), by = .(target = V1)][data.table(target = targets.v), on = c("target")]
# target hit.by.shooters
# 1: 1 1
# 2: 2 1;2;3
# 3: 3 2;3
# 4: 4 <NA>
# 5: 5 1
# 6: 6 1;2
# 7: 7 <NA>
# 8: 8 2
# 9: 9 1;2
# 10: 10 1
Une autre possibilité data tidyverse . Nous créons d'abord un dataframe avec toutes les combinaisons possibles de Shooter et Targets , puis supprimons les lignes présentes dans mydf en utilisant anti_join code >, remplissez les cibles manquantes en les ajoutant en tant que NA et enfin résumez par cibles pour obtenir Shooters qui atteint la cible. set.seed(987)
mydf <- data.frame(Shooter=1:3,
Targets.missed=c(paste(sample(1:10,4),collapse=";"),
paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))
library(tidyverse)
crossing(Shooter = unique(mydf$Shooter), Targets.missed = 1:10) %>%
anti_join(mydf %>% separate_rows(Targets.missed) %>% mutate_all(as.numeric)) %>%
complete(Targets.missed = 1:10) %>%
group_by(Targets.missed) %>%
summarise(hit.by.Shooters = paste0(Shooter, collapse = ";"))
# Targets.missed hit.by.Shooters
# <int> <chr>
# 1 1 1;2
# 2 2 1;2
# 3 3 1
# 4 4 1
# 5 5 2
# 6 6 1;3
# 7 7 1;2
# 8 8 2
# 9 9 NA
#10 10 3
Permettez-moi de modifier pour
targetetshooterafin que ce soit plus facile à interpréterPeut-être la bibliothèque
(dplyr); mydf%>% Separate_rows (Misses)%>% group_by (Number = Misses)%>% summary (ID = paste (unique (ID), collapse = ";"))Voir la modification au cas où; l'esprit que nous regardons des choses opposées ... dans la première trame de données, les cibles sont manquées, dans la seconde, je veux regarder les cibles touchées