5
library(tidyverse)
df <- tibble(col1 = c("A", "B", "C"),
             col2 = c(NA, Inf, 5))
#> # A tibble: 3 x 2
#>   col1   col2
#>   <chr> <dbl>
#> 1 A        NA
#> 2 B       Inf
#> 3 C         5

I can use the base R is.na() function to easily replace NAs with 0s, shown below:

df %>% replace(is.na(.), 0)
#> # A tibble: 3 x 2
#>   col1   col2
#>   <chr> <dbl>
#> 1 A         0
#> 2 B       Inf
#> 3 C         5

If I try to duplicate this logic with is.infinite() things break:

df %>% replace(is.infinite(.), 1)
#> Error in is.infinite(.) : default method not implemented for type 'list'

Looking at this older answer about Inf and R data frames I can hack together the solution shown below. This takes my original data frame and turns all NA into 0 and all Inf into 1. Why doesn't is.infinite() behave like is.na() and what is (perhaps) a better way to do what I want?

df %>% 
  replace(is.na(.), 0) %>% 
  mutate_if(is.numeric, list(~na_if(abs(.), Inf))) %>%  # line 3
  replace(is.na(.), 1)
#> # A tibble: 3 x 2
#>   col1   col2
#>   <chr> <dbl>
#> 1 A         0
#> 2 B         1
#> 3 C         5
Display name
  • 4,153
  • 5
  • 27
  • 75
  • 1
    If you check `?is.infinite` - `x - R object to be tested: the default methods handle atomic vectors.` where `?is.na` have methods for `matrix/data.frame/vector`. i.e. `x - an R object to be tested: the default method for is.na and anyNA handle atomic vectors, lists, pairlists, and NULL`. – akrun Nov 13 '19 at 19:02
  • 1
    You can try `df %>% mutate_if(is.numeric, replace_na, 0) %>% mutate_if(is.numeric, ~ replace(., is.infinite(.), 1))` – akrun Nov 13 '19 at 19:05
  • 2
    You could do `df %>% replace(sapply(., is.infinite), 1)` – MrFlick Nov 13 '19 at 19:18
  • Thanks, slight correction though, it'd be this; `df %>% replace(is.na(.), 0) %>% replace(sapply(., is.infinite), 1)`. – Display name Nov 14 '19 at 17:19

1 Answers1

6

The is.infinite expects the input 'x' to be atomic vector according to ?is.infinite

x- object to be tested: the default methods handle atomic vectors.

whereas ?is.na can take a vector, matrix, data.frame as input

an R object to be tested: the default method for is.na and anyNA handle atomic vectors, lists, pairlists, and NULL

Also, by checking the methods,

methods('is.na')
#[1] is.na.data.frame      is.na.data.table*     is.na.numeric_version is.na.POSIXlt         is.na.raster*         is.na.vctrs_vctr*    

methods('is.infinite') # only for vectors
#[1] is.infinite.vctrs_vctr*

We can modify the replace in the code to

library(dplyr)
df %>% 
    mutate_if(is.numeric, ~ replace_na(., 0) %>% 
                             replace(., is.infinite(.), 1))
# A tibble: 3 x 2
#  col1   col2
#  <chr> <dbl>
#1 A         0
#2 B         1
#3 C         5
akrun
  • 874,273
  • 37
  • 540
  • 662