2
votes

Sélectionnez les valeurs d'une ligne selon que l'autre ligne est unique ou non

J'aurais besoin de créer une nouvelle colonne dans mes données, qui serait égale à la valeur «tendre» au cas où «id» n'apparaît qu'une seule fois, et à la valeur «lot» si ce n'est pas le cas. Je ne peux rien faire concernant NA, car les données sont incomplètes et il y a beaucoup d'AN là-dedans. Mon idée était de faire que si 'id' est unique, alors sélectionnez

data.frame('id'=c(1,1,2,3,3,4), 'lot'=c(10,20,NA,40,50,NA), 
           'tender'=c(30,30,30,90,90,40),'price'=c(10,20,30,40,50,40))

A je m'attends à ce que la sortie soit:

df <- data.frame('id'=c(1,1,2,3,3,4), 
                 'lot'=c(10,20,NA,40,50,NA), 'tender'=c(30,30,30,90,90,40))

Merci pour toute aide

r

7 commentaires

Vous aurez peut-être besoin de df%>% mutate (price = coalesce (lot, tender))


Ou si nous passons par la condition df%>% group_by (id)%>% mutate (price = case_when (n () == 1 ~ tender, TRUE ~ lot))


Cela ne remplacerait-il pas simplement les AN par la valeur «d'appel d'offres»? Je ne peux pas faire cela, comme je l'ai mentionné, il y a beaucoup d'AN qui manquent simplement au hasard, pas parce que la valeur de «soumission» y appartient.


Je montre deux méthodes 1) basées sur les données, 2) basées sur la logique que vous avez mentionnée


Oui désolé, le second n'était pas là quand j'ai commencé à écrire: D


Vous pouvez le rendre plus robusst avec une vérification supplémentaire df%>% group_by (id)%>% mutate (price = case_when (n () == 1 & is.na (lot) ~ tendre, TRUE ~ lot) ) Faites-moi savoir si cela fonctionne


Peut confirmer que cela fonctionne, merci! (mon ensemble de données est énorme, il a fallu environ 5 minutes pour créer la nouvelle colonne lol)


3 Réponses :


2
votes

Selon la condition, nous pouvons faire un groupe par case_when

df %>%
   mutate(price = coalesce(lot, tender))

Avec l'exemple actuel de l'OP, coalesce fonctionnerait également

library(dplyr)
df %>% 
  group_by(id) %>%
  mutate(price = case_when(n() ==1 & is.na(lot) ~ tender, TRUE ~ lot))


2 commentaires

y a-t-il un avantage à utiliser case_when ici au lieu de ifelse , ou est-ce juste un cas de préférence?


@RussThomas Selon ? Case_when Cette fonction vous permet de vectoriser plusieurs instructions if_else (). . Mais ce n'était pas la raison pour laquelle je l'ai utilisé ici. C'était le premier que mes mains tapaient, alors je l'ai suivi



2
votes

Nous pouvons faire ceci:

# # A tibble: 6 x 4
# # Groups:   id [4]
#      id   lot tender price
#   <dbl> <dbl>  <dbl> <dbl>
# 1     1    10     30    10
# 2     1    20     30    20
# 3     2    NA     30    30
# 4     3    40     90    40
# 5     3    50     90    50
# 6     4    NA     40    40

Ou dans dplyr la solution serait:

library(dplyr)
df %>% 
  rowwise() %>% 
  mutate(price = min(lot, tender, na.rm = TRUE))
df$price <- apply(df, 1, function(x) min(x["lot"], x["tender"], na.rm = TRUE))


2 commentaires

Que faire s'il existe un id avec 1 ligne et un offre> lot (comme pour toutes les lignes dans les données d'exemple)?


@IceCreamToucan Je pense que tendre est le lot cumulatif (sorte de) donc je ne vois pas la possibilité du cas que vous avez présenté. OP peut vérifier / annuler cela.



0
votes

Sur la base de cette description, vous pouvez utiliser une instruction if sur la taille du groupe avec data.table

J'aurais besoin de créer une nouvelle colonne dans mes données, qui serait égale à la valeur 'soumissionner' au cas où 'id' n'apparaît qu'une seule fois, et au 'lot' valeur au cas où ce ne serait pas le cas.

library(data.table)
setDT(df)

df[, price := if(.N == 1) tender else lot, by = id]
#    id lot tender price
# 1:  1  10     30    10
# 2:  1  20     30    20
# 3:  2  NA     30    30
# 4:  3  40     90    40
# 5:  3  50     90    50
# 6:  4  NA     40    40


0 commentaires