R Заменить NA для всех столбцов, кроме * - PullRequest
3 голосов
/ 01 мая 2020
library(tidyverse)
df <- tibble(Date = c(rep(as.Date("2020-01-01"), 3), NA),
             col1 = 1:4,
             thisCol = c(NA, 8, NA, 3),
             thatCol = 25:28,
             col999 = rep(99, 4))
#> # A tibble: 4 x 5
#>   Date        col1  thisCol thatCol col999
#>   <date>     <int>    <dbl>   <int>  <dbl>
#> 1 2020-01-01     1       NA      25     99
#> 2 2020-01-01     2        8      26     99
#> 3 2020-01-01     3       NA      27     99
#> 4 NA             4        3      28     99

Мой фактический фрейм данных R содержит сотни столбцов, которые не имеют точных имен, но могут быть аппроксимированы приведенным выше фреймом df.

Я хочу заменить все значения NA с 0, за исключением нескольких столбцов (в моем примере я хочу опустить столбец Date и столбец thatCol. Я хотел бы сделать это следующим образом:

df %>% replace(is.na(.), 0)
#> Error: Assigned data `values` must be compatible with existing data.
#> i Error occurred for column `Date`.
#> x Can't convert <double> to <date>.
#> Run `rlang::last_error()` to see where the error occurred.

А мои неудачные идеи для выполнения «все, кроме» замены NA показаны ниже.

df %>% replace(is.na(c(., -c(Date, thatCol)), 0))
df %>% replace_na(list([, c(2:3, 5)] = 0))
df %>% replace_na(list(everything(-c(Date, thatCol)) = 0))

Есть ли способ выбрать все, НО так, как мне нужно? Есть сотни столбцов именуется непоследовательно, поэтому вводить их по одному не практично.

Ответы [ 5 ]

2 голосов
/ 01 мая 2020

Другое решение base:

 to_change<-grep("^(this|col)",names(df))
   df[to_change]<- sapply(df[to_change],function(x) replace(x,is.na(x),0))
    df
    # A tibble: 4 x 5
      Date        col1 thisCol thatCol col999
      <date>     <dbl>   <dbl>   <int>  <dbl>
    1 2020-01-01     1       0      25     99
    2 2020-01-01     2       8      26     99
    3 2020-01-01     3       0      27     99
    4 NA             0       3      28     99

Данные (я изменил одно значение):

df <- structure(list(Date = structure(c(18262, 18262, 18262, NA), class = "Date"), 
    col1 = c(1L, 2L, 3L, NA), thisCol = c(NA, 8, NA, 3), thatCol = 25:28, 
    col999 = c(99, 99, 99, 99)), row.names = c(NA, -4L), class = c("tbl_df", 
"tbl", "data.frame"))
2 голосов
/ 01 мая 2020

Вы можете использовать mutate_at:

library(dplyr)

Удалить их по имени

df %>% mutate_at(vars(-c(Date, thatCol)), ~replace(., is.na(.), 0))

Удалить их по позиции

df %>% mutate_at(-c(1,4), ~replace(., is.na(.), 0))

Выбрать их по имени

df %>% mutate_at(vars(col1, thisCol, col999), ~replace(., is.na(.), 0))

Выберите их по позиции

df %>% mutate_at(c(2, 3, 5), ~replace(., is.na(.), 0))

Если вы хотите использовать replace_na

df %>% mutate_at(vars(-c(Date, thatCol)), tidyr::replace_na, 0)

Обратите внимание, что mutate_at скоро будет быть заменен на across в dplyr 1.0.0.

1 голос
/ 01 мая 2020

replace работает с data.frame, поэтому мы можем просто выполнить замену по индексу и обновить исходный набор данных

df[-c(1, 4)] <- replace(df[-c(1, 4)], is.na(df[-c(1, 4)]), 0)

или использовать replace_na с across (из новый dplyr)

library(dplyr)
library(tidyr)
df %>% 
     mutate(across(-c(Date, thatCol), ~ replace_na(., 0)))
1 голос
/ 01 мая 2020

У вас есть несколько вариантов здесь на основе data.table.

Один из самых крутых вариантов: setnafill (версия> = 1.12.4):

library(data.table)
setDT(df)

data.table::setnafill(df,fill = 0, cols = colnames(df)[!(colnames(df) %in% c("Date", thatCol)]))

Обратите внимание, что ваш фрейм данных обновляется по ссылке.

0 голосов
/ 01 мая 2020

Если вы знаете, что не хотите менять, вы можете сделать это так:

df <- tibble(Date = c(rep(as.Date("2020-01-01"), 3), NA),
             col1 = 1:4,
             thisCol = c(NA, 8, NA, 3),
             thatCol = 25:28,
             col999 = rep(99, 4))


#dplyr
df_nonreplace <- select(df, c("Date", "thatCol"))

df_replace <- df[ ,!names(df) %in% names(df_nonreplace)]

df_replace[is.na(df_replace)] <- 0

df <- cbind(df_nonreplace, df_replace)


> head(df)
        Date thatCol col1 thisCol col999
1 2020-01-01      25    1       0     99
2 2020-01-01      26    2       8     99
3 2020-01-01      27    3       0     99
4       <NA>      28    4       3     99
...