Home > front end >  Is there a way to round factors throughout a dataframe using R?
Is there a way to round factors throughout a dataframe using R?

Time:12-01

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 rounding 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_detectthe 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),
                         .)))
  •  Tags:  
  • r
  • Related