web-dev-qa-db-fra.com

Comment créer une nouvelle colonne basée sur plusieurs conditions de plusieurs colonnes?

J'essaie d'ajouter une nouvelle colonne à un cadre de données en fonction de plusieurs conditions d'autres colonnes. J'ai les données suivantes:

> commute <- c("walk", "bike", "subway", "drive", "ferry", "walk", "bike", "subway", "drive", "ferry", "walk", "bike", "subway", "drive", "ferry")
> kids <- c("Yes", "Yes", "No", "No", "Yes", "Yes", "No", "No", "Yes", "Yes", "No", "No", "Yes", "No", "Yes")
> distance <- c(1, 12, 5, 25, 7, 2, "", 8, 19, 7, "", 4, 16, 12, 7)
> 
> df = data.frame(commute, kids, distance)
> df
   commute kids distance
1     walk  Yes        1
2     bike  Yes       12
3   subway   No        5
4    drive   No       25
5    ferry  Yes        7
6     walk  Yes        2
7     bike   No         
8   subway   No        8
9    drive  Yes       19
10   ferry  Yes        7
11    walk   No         
12    bike   No        4
13  subway  Yes       16
14   drive   No       12
15   ferry  Yes        7

Si les trois conditions suivantes sont remplies:

commute = walk OR bike OR subway OR ferry
AND
kids = Yes
AND
distance is less than 10

Ensuite, j'aimerais qu'une nouvelle colonne appelée get.flyer soit égale à "Oui". Le bloc de données final devrait ressembler à ceci:

   commute kids distance get.flyer
1     walk  Yes        1       Yes
2     bike  Yes       12       Yes
3   subway   No        5          
4    drive   No       25          
5    ferry  Yes        7       Yes
6     walk  Yes        2       Yes
7     bike   No                   
8   subway   No        8          
9    drive  Yes       19          
10   ferry  Yes        7       Yes
11    walk   No                   
12    bike   No        4          
13  subway  Yes       16       Yes
14   drive   No       12          
15   ferry  Yes        7       Yes
5
Ankie

Nous pouvons utiliser %in% pour comparer plusieurs éléments d'une colonne, & pour vérifier si les deux conditions sont VRAI.

library(dplyr)
df %>%
     mutate(get.flyer = c("", "Yes")[(commute %in% c("walk", "bike", "subway", "ferry") & 
           as.character(kids) == "Yes" & 
           as.numeric(as.character(distance)) < 10)+1] )

Il est préférable de créer le data.frame avec stringsAsFactors=FALSE car il s'agit par défaut de TRUE. Si nous vérifions la str(df), nous pouvons constater que toutes les colonnes sont des classes factor. De même, s'il existe des valeurs manquantes, vous pouvez utiliser NA au lieu de "" pour éviter de convertir la class d'une colonne numeric en quelque chose d'autre.

Si nous réécrivons la création de 'df'

distance <- c(1, 12, 5, 25, 7, 2, NA, 8, 19, 7, NA, 4, 16, 12, 7)
df1 <- data.frame(commute, kids, distance, stringsAsFactors=FALSE)

le code ci-dessus peut être simplifié

df1 %>%
    mutate(get.flyer = c("", "Yes")[(commute %in% c("walk", "bike", "subway", "ferry") &
        kids == "Yes" &
        distance < 10)+1] )

Pour une meilleure compréhension, certaines personnes préfèrent ifelse

df1 %>% 
   mutate(get.flyer = ifelse(commute %in% c("walk", "bike", "subway", "ferry") & 
                kids == "Yes" &
                distance < 10, 
                          "Yes", ""))

Cela peut aussi être fait facilement avec les méthodes base R

df1$get.flyer <- with(df1, ifelse(commute %in% c("walk", "bike", "subway", "ferry") & 
              kids == "Yes" & 
              distance < 10, 
                       "Yes", ""))
8
akrun

La solution est déjà indiquée par @akrun. Je voudrais le présenter d'une manière plus "enveloppée".

Vous pouvez utiliser l'instruction ifelse pour créer une colonne en fonction d'une ou de plusieurs conditions. Mais vous devez d’abord changer le «codage» des valeurs manquantes dans la colonne de distance. Vous avez utilisé "" pour indiquer une valeur manquante. Toutefois, la colonne entière est convertie en string et empêche la comparaison numérique (distance < 10 n'est pas possible). La manière R d'indiquer une valeur manquante est NA, votre définition de colonne de distance devrait être:

distance <- c(1, 12, 5, 25, 7, 2, NA, 8, 19, 7, NA, 4, 16, 12, 7)

La déclaration ifelse ressemble alors à ceci:

df$get.flyer <- ifelse(
    ( 
        (df$commute %in% c("walk", "bike", "subway", "ferry")) &
        (df$kids == "Yes")                                     &
        (df$distance < 10)
    ),
    1,  # if condition is met, put 1
    0   # else put 0
)

Facultatif: Pensez également à coder vos autres colonnes différemment:

  • vous pouvez utiliser TRUE et FALSE au lieu de "Oui" et "Non" pour la variable kids
  • vous pouvez utiliser un factor pour faire la navette
6
Tw UxTLi51Nus

Exemple, vérifiez si first_column_name est contenu dans second_column_name et écrivez le résultat dans new_column

df$new_column <- apply(df, 1, function(x) grepl(x['first_column_name'], x['second_column_name'], fixed = TRUE))

Détails:

df$new_column <- # create a new column with name new_column on df
apply(df, 1 # `1` means for each row, `apply(df` means apply the following function on df
function(x) # Function definition to apply on each row, `x` means input row for each row.
grepl(x['first_column_name'], x['second_column_name'], fixed = TRUE)) # Body of function to apply, basically run grepl to find if first_column_name is in second_column_name, fixed = TRUE means don't use regular expression just the plain text from first_column_name.
0
Tomer Ben David