This seems too basic to not be found in a search, but maybe I didn't use the correct search terms on Google.
I want to normalize a numeric column. When I modify that column with mutate(across(.., scale))
I get [,1]
added to the header. Why is that?
library(dplyr, warn.conflicts = FALSE)
mtcars_mpg_only <-
mtcars %>%
as_tibble() %>%
select(mpg)
mtcars_mpg_only %>%
as_tibble() %>%
mutate(across(mpg, scale))
#> # A tibble: 32 x 1
#> mpg[,1]
#> <dbl>
#> 1 0.151
#> 2 0.151
#> 3 0.450
#> 4 0.217
#> 5 -0.231
#> 6 -0.330
#> 7 -0.961
#> 8 0.715
#> 9 0.450
#> 10 -0.148
#> # ... with 22 more rows
But if I use a different function rather than scale()
(e.g., log()
), then the column header remains as-is:
mtcars_mpg_only %>%
as_tibble() %>%
mutate(across(mpg, log))
#> # A tibble: 32 x 1
#> mpg
#> <dbl>
#> 1 3.04
#> 2 3.04
#> 3 3.13
#> 4 3.06
#> 5 2.93
#> 6 2.90
#> 7 2.66
#> 8 3.19
#> 9 3.13
#> 10 2.95
#> # ... with 22 more rows
I know how to remove/rename [,1]
after the fact, but my question is why it's created to begin with?
CodePudding user response:
It is because scale returns a matrix whereas log returns a plain vector. The mpg[, 1] is actually a matrix within a data.frame. See ?scale for the definition of its value.
class(scale(mtcars$mpg))
## [1] "matrix" "array"
class(log(mtcars$mpg))
## [1] "numeric"
Convert the matrix to a plain vector to avoid this, e.g.
mtcars_mpg_only %>%
mutate(across(mpg, ~ c(scale(.))))
# or extracting first column
mtcars_mpg_only %>%
mutate(across(mpg, ~ scale(.)[, 1]))
# or normalizing using mean and sd
mtcars_mpg_only %>%
mutate(across(mpg, ~ (. - mean(.)) / sd(.)))
# or without across
mtcars_mpg_only %>%
mutate(mpg = c(scale(mpg)))
# or using base R
mtcars_mpg_only |>
transform(mpg = c(scale(mpg)))