Как передать сообщения if в R - PullRequest
2 голосов
/ 07 января 2020

У меня есть данные из моих учетных записей Facebook, Twitter, Instagram, Youtube и LinkedIn, которые я хотел бы проанализировать. У меня есть фрейм данных, подобный следующему:

df <- data.frame(tw_likes = c(5,4,6,NA,NA,NA,NA,NA,NA), 
                 tw_comments = c(3,5,NA,NA,NA,NA,NA,NA,NA), 
                 fb_likes = c(NA,NA,NA,7,4,8,NA,NA,NA), 
                 fb_comments = c(NA,NA,NA,NA,NA,7,NA,NA,NA), 
                 ig_likes = c(NA,NA,NA,NA,NA,NA,NA,NA,5), 
                 ig_comments = c(NA,NA,NA,NA,NA,NA,43,4,2))

я хочу создать дополнительный столбец Platform, который будет принимать значения «Twitter», «Facebook» или «Instagram» на основе приведенный выше фрейм данных.

Мои тактики c были следующими:

for(i in 1:nrow(df){
     if(!is.na(df$tw_likes[i]) | !is.na(df$tw_comments[i])){
          df$Platform[i] <- "Twitter"
     }
     else if(!is.na(df$fb_likes[i]) | !is.na(df$fb_comments[i])){
          df$Platform[i] <- "Facebook"
     }
     else if(!is.na(df$ig_likes[i]) | !is.na(df$ig_comments[i])){
          df$Platform[i] <- "Instagram"
     }
}

Это работает, но становится сложнее для чтения. В действительности у меня есть больше столбцов и больше социальных медиа-платформ, поэтому есть ли способ передачи данных, чтобы мне, по крайней мере, не приходилось писать df$ столько раз?

У меня была еще одна мысль: если я не могу удалить df$ s, могу ли я объединить операторы !is.na() в один оператор на оператор if?

Ответы [ 3 ]

5 голосов
/ 07 января 2020

Вот один из способов в base R разбить набор данных на list столбцов с одинаковыми префиксами (удалив подстроку суффикса из имен столбцов), выполните rowSums, чтобы создать логический matrix, примените max.col чтобы получить положение столбца для каждой строки и изменить этот индекс, передав вектор значений замены в том же порядке имен разделенных столбцов

i1 <- max.col(sapply(split.default(df, sub("_.*", "", names(df))),
        function(x) rowSums(!is.na(x)) > 0 ), 'first')
df$Platform <- c("Facebook", "Instagram", "Twitter")[i1]
df$Platform
#[1] "Twitter"   "Twitter"   "Twitter"   "Facebook"  "Facebook"  
#[6]   "Facebook"  "Instagram" "Instagram" "Instagram"
4 голосов
/ 07 января 2020

Вот вариант с dplyr s case_when()

df %>% 
  mutate(Plataform = case_when(
    !is.na(tw_likes) | !is.na(tw_comments) ~ "Twitter",
    !is.na(fb_likes) | !is.na(fb_comments) ~ "Facebook",
    !is.na(ig_likes) | !is.na(ig_comments) ~ "Instagram"))
2 голосов
/ 07 января 2020

Вот еще один подход, использующий dplyr и tidyr, чтобы вывести данные в длинный формат, отфильтровать пробелы и добавить более длинное имя на основе таблицы поиска:

library(tidyr); library(dplyr)
df %>%
  pivot_longer(cols = everything(), 
               names_to = c("pltfm", "stat"),
               names_sep = "_",
               values_to = "value") %>%
  filter(!is.na(value)) %>%
  left_join(
    tibble(pltfm = c("tw", "fb", "ig"),
           Platform = c("Twitter", "Facebook", "Instagram"))
  )


#Joining, by = "pltfm"
## A tibble: 13 x 4
#   pltfm stat     value Platform 
#   <chr> <chr>    <dbl> <chr>    
# 1 tw    likes        5 Twitter  
# 2 tw    comments     3 Twitter  
# 3 tw    likes        4 Twitter  
# 4 tw    comments     5 Twitter  
# 5 tw    likes        6 Twitter  
# 6 fb    likes        7 Facebook 
# 7 fb    likes        4 Facebook 
# 8 fb    likes        8 Facebook 
# 9 fb    comments     7 Facebook 
#10 ig    comments    43 Instagram
#11 ig    comments     4 Instagram
#12 ig    likes        5 Instagram
#13 ig    comments     2 Instagram
...