Как изменить NA на нескольких строках (по строкам) в таблице - PullRequest
3 голосов
/ 08 февраля 2020

Я провожу некоторое время, пытаясь выяснить, как изменить NA значения в нескольких строках в перспективе строк в tibble, tibble имеет 3 наблюдения и 6 переменных, генерируемых ниже:

df <- data.frame(ID = c(1, 2, 3),
                 Score1 = c(90, 80, 70),
                 Score2 = c(66, 78, 86),
                 Score3 = c(NA, 86, 96),
                 Score4 = c(84, 76, 72),
                 Score5 = c(92, NA, 74))
sample_tibble <- as_tibble(df)

tibble выглядит как

# A tibble: 3 x 6
     ID Score1 Score2 Score3 Score4 Score5
  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1     1     90     66     NA     84     92
2     2     80     78     86     76     NA
3     3     70     86     96     72     74

Я должен использовать функции из tidyverse (например, mutate, mutate_at, rowwise .. et c.), Цель - заменить NA в строке 1 (в столбце Score3) и строке 2 (в столбце Score5) на mean строки 1 и строки 2 соответственно (mean, рассчитанные с другими значениями в строке, а не NA), поэтому идеальный результат должен быть после mutate

# A tibble: 3 x 6
     ID Score1 Score2 Score3 Score4 Score5
  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1     1     90     66     83     84     92
2     2     80     78     86     76     80
3     3     70     86     96     72     74

Первые NA заменить на mean(c(90, 66, NA, 84, 92), na.rm = TRUE) как 83
Вторые NA заменить на mean(c(80, 78, 86, 76, NA), na.rm = TRUE) как 80

Попробовал некоторый код, как показано ниже, а также проверьте предыдущий do c как Примените функцию к каждой строке матрицы или фрейма данных или dplyr - используя mutate () как rowmeans () , но код никогда не работает, так как я могу определить тело mutate function

sample_tibble[, -1] %>% rowwise() %>% mutate(...)

Не ограничено * 1 042 * на rowwise или mutate (например, mutate_at также хорошо), есть ли какое-либо решение, способное изменить строку 1 и строку 2 для достижения целевого формата (Его отлично подходит для изменения одновременно , а не использовать for loop, чтобы мутировать дважды), оцените любые решения!

Ответы [ 2 ]

4 голосов
/ 08 февраля 2020

Немного неэффективным способом было бы gather и group_by it:

sample_tibble %>%
  tidyr::gather(k, v, -ID) %>%
  group_by(ID) %>%
  mutate(v = if_else(is.na(v), mean(v, na.rm = TRUE), v)) %>%
  ungroup() %>%
  tidyr::spread(k, v)
# # A tibble: 3 x 6
#      ID Score1 Score2 Score3 Score4 Score5
#   <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
# 1     1     90     66     83     84     92
# 2     2     80     78     86     76     80
# 3     3     70     86     96     72     74

Как RonakShah также напомнил мне, gather / spread можно заменить более новым (и более Featureful) двоюродные братья: pivot_longer / pivot_wider.

Другой метод использует apply:

sample_tibble %>%
  mutate(mu = apply(.[,-1], 1, mean, na.rm = TRUE)) %>%
  ### similarly, and faster, thanks RonakShah
  # mutate(mu = rowMeans(.[,-1], na.rm = TRUE)) %>%
  mutate_at(vars(starts_with("Score")), ~ if_else(is.na(.), mu, .)) %>%
  select(-mu)

Предостережение с этим: .[,-1] явно использует каждый столбец, кроме первый; Если у вас есть другие столбцы, которые не были упомянуты в вопросе, то это, безусловно, будет использовать больше данных, чем вы предполагали. К сожалению, я не знаю способа использования : -ранжирования в этом решении, так как это было бы понятнее.

1 голос
/ 08 февраля 2020

Одним из подходов, использующих немного математики, может быть:

df %>%
 mutate_at(vars(-1), 
           ~ pmax(is.na(.)*rowMeans(select(df, -1), na.rm = TRUE), 
                  (!is.na(.))*., 
                  na.rm = TRUE))


  ID Score1 Score2 Score3 Score4 Score5
1  1     90     66     83     84     92
2  2     80     78     86     76     80
3  3     70     86     96     72     74
...