Замена NA на определенное условие в R

В случае, если 2017 год — это NA, а столбцы 2015 и 2016 годов имеют значение, я хочу присвоить их среднее значение 2017 году на основе той же строки.

Index   2015            2016            2017
1       NA              6355698         10107023
2       13000000        73050000        NA
4       NA              NA              NA
5       10500000        NA              8000000
6       331000000       659000000       1040000000
7       55500000        NA              32032920
8       NA              NA              20000000
9       2521880         5061370         7044288
...

Вот что я пробовал, не получилось!

ind <- which(is.na(df), arr.ind=TRUE)
df[ind] <- rowMeans(df,  na.rm = TRUE)[ind[,1]]

Кроме того, если у нас есть значения в столбцах 2015 и 2017 годов, а 2016 год — NA, я хочу присвоить их среднее значение столбцу 2016 года на основе той же строки. Любая помощь будет оценена по достоинству!


person kimi-finn379    schedule 17.07.2018    source источник


Ответы (1)


Отказ от ответственности: мне не совсем понятно, каков ваш ожидаемый результат. Приведенное ниже решение основано на предположении, что вы хотите заменить значения NA либо средним значением всех значений за каждый год, либо средним значением всех значений для каждого Index.

Вот вариант tidyverse, сначала распространяющийся от широкого к длинному, заменяющий NAs средним значением за год и, наконец, конвертирующий обратно из длинного в широкий.

library(tidyverse)
df %>%
    gather(year, value, -Index) %>%
    group_by(year) %>%
    mutate(value = ifelse(is.na(value), mean(value, na.rm = T), value)) %>%
    spread(year, value)
## A tibble: 8 x 4
#  Index     `2015`     `2016`      `2017`
#  <int>      <dbl>      <dbl>       <dbl>
#1     1 115507293.   6355698.   10107023.
#2     2  13000000. 223472356.  186197372.
#3     4 115507293. 223472356.  186197372.
#4     5 115507293. 223472356.    8000000.
#5     6 331000000. 659000000. 1040000000.
#6     7 115507293. 223472356.   32032920.
#7     8 115507293. 223472356.   20000000.
#8     9   2521880.   5061370.    7044288.

Обратите внимание, что здесь мы заменяем NAs средним значением в год. Если вместо этого вы хотите заменить NAs средним значением на Index значение, просто замените group_by(year) на group_by(Index):

df %>%
    gather(year, value, -Index) %>%
    group_by(Index) %>%
    mutate(value = ifelse(is.na(value), mean(value, na.rm = T), value)) %>%
    spread(year, value)
## A tibble: 8 x 4
## Groups:   Index [8]
#  Index     `2015`     `2016`      `2017`
#  <int>      <dbl>      <dbl>       <dbl>
#1     1   8231360.   6355698.   10107023.
#2     2  13000000.  13000000.   13000000.
#3     4       NaN        NaN         NaN
#4     5   8000000.   8000000.    8000000.
#5     6 331000000. 659000000. 1040000000.
#6     7  32032920.  32032920.   32032920.
#7     8  20000000.  20000000.   20000000.
#8     9   2521880.   5061370.    7044288.

Обновлять

Чтобы заменить только NAs в столбце 2017 средним значением строки на основе значений 2015, 2016, которые вы можете сделать

df <- read_table("Index   2015            2016            2017
1       NA              6355698         10107023
2       13000000        73050000        NA
4       NA              NA              NA
5       10500000        NA              8000000
6       331000000       659000000       1040000000
7       55500000        NA              32032920
8       NA              NA              20000000
9       2521880         5061370         7044288")


df %>%
    mutate(`2017` = ifelse(is.na(`2017`), 0.5 * (`2015` + `2016`), `2017`))
## A tibble: 8 x 4
#  Index    `2015`    `2016`      `2017`
#  <int>     <int>     <int>       <dbl>
#1     1        NA   6355698   10107023.
#2     2  13000000  73050000   43025000.
#3     4        NA        NA         NA
#4     5  10500000        NA    8000000.
#5     6 331000000 659000000 1040000000.
#6     7  55500000        NA   32032920.
#7     8        NA        NA   20000000.
#8     9   2521880   5061370    7044288.

Пример данных

df <- read_table("Index   2015            2016            2017
1       NA              6355698         10107023
2       13000000        NA              NA
4       NA              NA              NA
5       NA              NA              8000000
6       331000000       659000000       1040000000
7       NA              NA              32032920
8       NA              NA              20000000
9       2521880         5061370         7044288")
person Maurits Evers    schedule 17.07.2018
comment
Должно быть group_by(Index)? Как OP ищет rowMeans? - person Roman; 17.07.2018
comment
@Джимбо Хм. Да, возможно. Я немного запутался, потому что в этом случае у Index = 4 будут все NA. Я сделаю заметку. - person Maurits Evers; 17.07.2018
comment
Спасибо, парни! Я отредактировал образец данных, потому что в предыдущем не было того, что я хочу, чтобы вы показали вам в качестве примера. - person kimi-finn379; 17.07.2018
comment
@ kimi-finn379 Значит, вы хотите заменить NA только на 2017 год? - person Maurits Evers; 17.07.2018
comment
Для 2017 и 2016 годов. Чтобы уточнить среднее значение столбцов, оно также должно быть основано на одной и той же строке. - person kimi-finn379; 17.07.2018
comment
Не ясно. В случае, если 2017 год — это NA, а столбцы 2015 и 2016 годов имеют значение, я хочу присвоить их среднее значение 2017 году на основе той же строки. Таким образом, вы хотите заменить только NA значения в столбце 2017. NA в столбцах 2015 и 2016 останутся прежними. Правильный? - person Maurits Evers; 17.07.2018
comment
@ kimi-finn379 Я включил обновление, в котором показываю, как заменить NAs в столбце 2017 средним значением строки из значений 2015/2016. - person Maurits Evers; 17.07.2018
comment
Да, это именно то, что я хочу. Извините за плохое объяснение. - person kimi-finn379; 17.07.2018
comment
@ kimi-finn379 Без проблем, пожалуйста! - person Maurits Evers; 17.07.2018
comment
Если я хочу удалить строки с 2 или 3 NA в столбце 2015, 2016, 2017. Что я могу сделать? - person kimi-finn379; 17.07.2018
comment
@ kimi-finn379 Чтобы удалить строки с >= 2 NAs в строке, вы можете сделать df[apply(df, 1, function(x) sum(is.na(x)) < 2), ] - person Maurits Evers; 17.07.2018