Reputation: 21
I am exploring the tidyverse package.
I am okay with the below code:
library(dslabs)
data("murders")
murders <- mutate(murders, rate = total / population * 100000)
murders
filter(murders, rate <= 0.71)
The pipe - Using the pipe the code is as below:
murders %>% select(state, region, rate) %>% filter(rate <= 0.71)
How can I format the rate from the current 7 decimal places to 2?
Upvotes: 0
Views: 273
Reputation: 5747
I presume that your desire is to just print these data with two decimal places and not to actually round them? If you do wish to round the data, that is simple:
Rounding
library(dplyr)
library(dslabs)
data("murders")
murders %>%
select(state, region, rate) %>%
filter(rate <= 0.71) %>%
mutate(rate = round(rate, 2))
state region rate
1 Hawaii West 0.51
2 Iowa North Central 0.69
3 New Hampshire Northeast 0.38
4 North Dakota North Central 0.59
5 Vermont Northeast 0.32
tibble workaround
If you do not wish to round the data, but you wish to only print two digits, you can do this by converting your data to a tibble
and setting the pillar.sigfig
option. Note that options(pillar.sigfig = 2)
prints two significant digits, not decimal places explicitly. So if your data had a value of 1.23345
it would print 1.2
. However, your rates are all less than one, so this should function as a workaround. You can control decimal places precisely using the vctrs
package, and that approach is below.
library(dplyr)
library(tibble)
library(dslabs)
data("murders")
options(pillar.sigfig = 2)
murders2 <- murders %>%
select(state, region, rate) %>%
filter(rate <= 0.71) %>%
tibble()
murders2
# A tibble: 5 x 3
state region rate
<chr> <fct> <dbl>
1 Hawaii West 0.51
2 Iowa North Central 0.69
3 New Hampshire Northeast 0.38
4 North Dakota North Central 0.59
5 Vermont Northeast 0.32
An important distinction about the second approach is that the underlying values are not changed. If you grab just on value from the tibble
, you get the full number of digits back:
murders2$rate[3]
[1] 0.3798036
Setting options(pillar.sigfig = )
changes a global option for the printing of all tibbles
. To resume normal behavior, set options(pillar.sigfig = NULL)
.
Note, setting a similar option for decimal places and not significant figures has been a feature request for the tibble
package (https://github.com/tidyverse/tibble/issues/772), but seems unlikely to be implemented at this time.
A better solution using vctrs
There is hope if your data is more complex! The vctrs
package allows you do define new vector classes with various behaviors (including printing a certain number of decimal places). In fact, setting decimal places is one of the two use case examples in vignette("s3-vector")
. Run the code from the vignette (reproduced below) to create the new class, then mutate
your column.
library(vctrs)
new_decimal <- function(x = double(), digits = 2L) {
vec_assert(x, ptype = double())
vec_assert(digits, ptype = integer(), size = 1)
new_vctr(x, digits = digits, class = "vctrs_decimal")
}
decimal <- function(x = double(), digits = 2L) {
x <- vec_cast(x, double())
digits <- vec_recycle(vec_cast(digits, integer()), 1L)
new_decimal(x, digits = digits)
}
digits <- function(x) attr(x, "digits")
format.vctrs_decimal <- function(x, ...) {
sprintf(paste0("%-0.", digits(x), "f"), x)
}
vec_ptype_abbr.vctrs_decimal <- function(x, ...) {
"dec"
}
murders3 <- murders %>%
select(state, region, rate) %>%
filter(rate <= 0.71) %>%
mutate(rate = decimal(rate, 2))
murders3
state region rate
1 Hawaii West 0.51
2 Iowa North Central 0.69
3 New Hampshire Northeast 0.38
4 North Dakota North Central 0.59
5 Vermont Northeast 0.32
This benefit of this vctrs
approach is that it handles any value and can be done without converting to a tibble
if you do not want to.
decimal(1.2345, 2)
<vctrs_decimal[1]>
[1] 1.23
Again, the full value is preserved, though you need to remove the class or change the digits
attribute to see more decimal places:
unclass(num)
[1] 1.2345
attr(,"digits")
[1] 2
attributes(num)$digits <- 4
num
<vctrs_decimal[1]>
[1] 1.2345
Upvotes: 1