I have a dataframe with a mix of characters and numbers in each column that are ultimately considered character columns like this:
df1 <- data.frame(
Group = c('Type', 'State', 'Roads'),
Value1 = c('A', 'Florida', 107.188887)
)
I want to round the number data points to the tenth digit, but this doesn't seem possible given they are intermingled with other data types. Is there a way to do this rounding using R? The result would look like this:
df_desired <- data.frame(
Group = c('Type', 'State', 'Roads'),
Value1 = c('A', 'Florida', 107.2)
)
I'd prefer to avoid pivoting the df if possible.
CodePudding user response:
Find the elements that are only numeric and do the round
ing in base R
itself
i1 <- grep("^[0-9.] $", df1$Value1)
df1$Value1[i1] <- round(as.numeric(df1$Value1[i1]), 1)
-output
> df1
Group Value1
1 Type A
2 State Florida
3 Roads 107.2
If it is an entire dataset, use lapply
df1[] <- lapply(df1, function(x) {
i1 <- grep("^[0-9.] $", x)
x[i1] <- round(as.numeric(x[i1]), 1)
x
})
-output
> df1
Group Value1
1 Type A
2 State Florida
3 Roads 107.2
CodePudding user response:
First str_detect
the numerical value, then str_extract
it, convert it to numeric with as.numeric
, and finally round
it:
library(stringr)
library(dplyr)
df1 %>%
mutate(Value1 = ifelse(str_detect(Value1, "^[\\d.] $"),
round(as.numeric(str_extract(Value1, "^[\\d.] $")),1),
Value1))
Group Value1
1 Type A
2 State Florida
3 Roads 107.2
EDIT:
If this type of edit needs to be done in several columns, you can mutate(across
:
df1 %>%
mutate(across(starts_with("V"),
~ifelse(str_detect(., "^[\\d.] $"),
round(as.numeric(str_extract(., "^[\\d.] $")),1),
.)))
df1 <- data.frame(
Group = c('Type', 'State', 'Roads'),
Value1 = c('A', 'Florida', 107.188887),
Value2 = c('B', 'California', 234.1229997)
)
This much more concise method works too (Warnings can be ignored):
df1 %>%
mutate(across(starts_with("V"),
~ifelse(str_detect(., "^[\\d.] $"),
round(as.numeric(.),1),
.)))