3
votes

convertir une trame de données de nombres «manqués» en une trame de données de nombres «frappés»

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 commentaires

Permettez-moi de modifier pour target et shooter afin que ce soit plus facile à interpréter


Peut-ê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


3 Réponses :


4
votes

Nous développons les données en divisant au ; 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 complete

mydf <- 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"))

Ou une autre option est 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')

et modifiez les noms des colonnes si nécessaire

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        


0 commentaires

1
votes

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


0 commentaires

1
votes

Une autre possibilité 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=";")))

data

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           


0 commentaires