2
votes

Comment reclasser / remplacer des valeurs en fonction de la priorité lorsqu'il y a des répétitions

J'ai un df où value indique l'état d'un drug:

  drug value
1    a   fda
2    a   fda
3    a   fda
4    d  case
5    d  case

Donc pour les médicaments, je veux remplacer tout répéter le médicament en fonction de l'ordre de priorité suivant pour valeur:

fda > trial > case > pre 

Par exemple, si le médicament d est «cas» ainsi que «pré», toute incidence de d sera reclassée comme «cas». La table finale devrait ressembler à ceci.

g1 = data.frame ( 
    drug = c('a','a','a','d','d'),
    value = c('fda','trial','case','case','pre')
)

drug value
1    a   fda
2    a trial
3    a  case
4    d  case
5    d   pre

Comment faire cela sans avoir à parcourir chaque médicament et à déterminer la priorité avant de le remplacer?


14 commentaires

Utilisez dplyr :: mutate (value = case_when (...)) ; c'est une copie de beaucoup de questions existantes.


Double possible de dplyr mutate avec des valeurs conditionnelles


@smci - à mon humble avis, ce n'est pas une dupe. Le traiter comme une variable ordinale semble plus simple que d'écrire plusieurs instructions case when.


@thelatemail: oui c'est certainement une dupe de beaucoup de questions existantes; il y a 10 686 appels (!) sur dplyr mutate seul et 469 appels sur dplyr mutate / case_when ou ifelse . Je les ai parcourus depuis un moment, la seule question est de savoir quelle est la meilleure cible de dupe. Pouvez-vous en choisir un?


@smci - aucune des 3 réponses ici n'a utilisé case_when ou ifelse, donc je pense que la logique n'est pas une bonne correspondance avec ce qui consiste essentiellement à prendre un minimum par groupe une fois que la variable ordonnée est définie. Il pourrait y avoir une correspondance, mais je n'ai pas beaucoup de chance de trouver quelque chose de très bon - stackoverflow.com/questions/39403317/… est une idée similaire mais pas tout à fait.


Il serait utile qu'Ahdee indique si chaque valeur de fda, ​​trial, case, pre est garantie d'exister, et dans cet ordre, pour chaque drogue . Ce n'est pas indiqué explicitement, mais les réponses semblent reposer sur cela. (Ouais @thelatemail si c'est une contrainte explicite ça change les réponses). Et si un médicament avait une entrée pour fda mais pas pour trial , par quoi devrions-nous alors remplacer case ? Ou le code peut-il supposer que cela ne peut pas arriver?


@smci - si c'est un facteur ordonné selon ma réponse, cela n'a pas d'importance. La valeur minimale sera la première dans l'ordre spécifié. Voir la modification de ma réponse.


@thelatemail: il incombe à l'OP d'énoncer clairement les contraintes de la question. Votre réponse est assez soignée, mais si quelqu'un convertit en chaîne / facteur non ordonné / ordinal puis exporte (par exemple en tant que csv) et relit, cela pourrait être fragile. Que se passe-t-il si un statut d'essai nouveau ou invisible est rencontré? etc.


@smci - s'il y a un nouveau statut d'essai de drogue invisible, j'imagine que tout code, qu'il soit basé sur des facteurs ou basé sur le cas / quand, devra changer pour en tenir compte.


HI remercie tout le monde pour votre aide dans ce domaine. J'ai essayé de parcourir les réponses précédentes, mais je n'ai pas pu en trouver une capable de résoudre mon problème jusqu'à présent. Pour répondre aux questions ci-dessus, il n'est pas garanti que les valeurs existent, mais comme indiqué par @smci, le facteur ordonné fonctionne indépendamment de la valeur manquante.


(Il y avait cette question , sauf en utilisant summary sur le facteur ordonné au lieu de mutate , et il s'agissait plus d'un ancien bogue dans dplyr 0.5.0, et il n'a pas de réponse, alors ne l'utilisez pas ).


Ok, j'ai rétracté mon vote close-as-dupe: il est préférable de le gérer avec un classement catégorique et min () . Le titre ne nous dit sérieusement pas de quoi il s'agit, au sens du code ...


@smci merci pour le suivi et les réponses ci-dessous ont énormément aidé. Vous ne savez pas comment modifier le titre? Aucune suggestion?


@Ahdee: bien sûr. si vous souhaitez modifier le titre pour être plus clair, veuillez le faire; seul l'OP est censé le faire une fois qu'une question a des réponses. Cela dépend de la manière dont vous souhaitez exposer votre problème; le titre actuel utilise un langage très vague; votre code implique également que drogue et valeur sont des chaînes, mais plus tard, les répondants en déduisent qu'il aurait été préférable de déclarer la valeur en tant que catégoriel ordonné, avec l'ordre de priorité spécifique que vous avez donné (donc min () fonctionne comme prévu). Il est peut-être préférable de demander "Comment représenter au mieux la colonne de dataframe lorsque je souhaite appliquer l'ordre de priorité à ses valeurs?"


3 Réponses :


3
votes

Mise à jour à l'aide d'un vecteur de carte, ce que je faisais, car je ne veux pas changer le type de colonnes.

mapvect=c(1,2,3,4)
names(mapvect)=c('pre','case','trial','fda')
g1$helpkey=mapvect[g1$value]

g1 %>% group_by(drug) %>% arrange(value)%>% dplyr::mutate(value=value[helpkey==max(helpkey)])
# A tibble: 5 x 3
# Groups:   drug [2]
drug value helpkey
<chr> <chr>   <dbl>
1     a   fda       2
2     d  case       2
3     a   fda       4
4     d  case       1
5     a   fda       3


2 commentaires

Ce n'est pas aussi bon que la réponse de @ thelatemail, cela crée un facteur non ordonné et repose sur l'ordre souhaité des valeurs se produisant dans l'ordre dans le dataframe; si cela ne se produit pas, il se brise. Une meilleure approche est classée par catégorie avec min .


Vous n'avez pas besoin de créer une colonne d'aide, ne pouvez-vous pas simplement opérer directement sur min (valeur) ? Quoi qu'il en soit, si vous le créez, vous souhaitez supprimer la colonne d'aide %>% select (-helpkey)



3
votes

Similaire à la réponse de @ Wen-Ben, avec les fonctions base , vous pouvez également faire:

g1$value <- factor(g1$value, levels = c("fda", "trial", "case", "pre"))
g1 <- g1[order(g1$value),]
g1$value <- g1[match(g1$drug, g1$drug), "value"]


0 commentaires

4
votes

Comme il s'agit d'une variable ordinale, vous pouvez faire de g1 $ value un facteur ordonné comme classe correspondante. Ensuite, vous pouvez utiliser des fonctions telles que min et max comme vous le feriez avec un numérique:

g2 = data.frame ( 
    drug = c( "a","a","a","d","d","e","e","e"),
    value = c("fda","trial","case","case","pre","pre","fda","case")
)

#  drug value
#1    a   fda
#2    a trial
#3    a  case
#4    d  case
#5    d   pre
#6    e   pre
#7    e   fda
#8    e  case

g2 %>%
  mutate(value = ordered(value, levels = c("fda", "trial", "case", "pre"))) %>%
  group_by(drug) %>%
  mutate(value = min(value))

## A tibble: 8 x 2
## Groups:   drug [3]
#  drug  value
#  <fct> <ord>
#1 a     fda  
#2 a     fda  
#3 a     fda  
#4 d     case 
#5 d     case 
#6 e     fda  
#7 e     fda  
#8 e     fda 

Ou dans dplyr speak:

g1 %>%
  mutate(value = ordered(value, levels = c("fda", "trial", "case", "pre"))) %>%
  group_by(drug) %>%
  mutate(value = min(value))

L'ordre dans l'ensemble de données et la plage de valeurs présentes dans tout groupe médicament ne devraient pas affecter ce résultat:

g1$value <- ordered(g1$value, levels = c("fda", "trial", "case", "pre"))
g1$value
#[1] fda   trial case  case  pre  
#Levels: fda < trial < case < pre
g1$value <- ave(g1$value, g1$drug, FUN=min)
g1
#  drug value
#1    a   fda
#2    a   fda
#3    a   fda
#4    d  case
#5    d  case


1 commentaires

c'est super et ça marche bien. J'aime particulièrement le premier exemple car il ne nécessite que la base R et cela a beaucoup de sens. Répondez ci-dessus à propos des dups, bien qu'il y ait beaucoup de questions similaires, je ne peux pas en trouver une qui aurait pu répondre à ce dont j'avais besoin.