Home > Net >  R: order the level of a factor vector based on the first number in the factor
R: order the level of a factor vector based on the first number in the factor

Time:09-21

I want to order the level of a factor vector based on the first number in the factor.

Below is the example:

FC <- factor(c("R: 12.22 P: 170.0", "R: 12.98 P: 189.1", "R: 2.55 P: 286", "R: 12.22 P: 170.0", "R: 12.98 P: 189.1", "R: 2.55 P: 286"))

## the original level oder 
FC
[1] R: 12.22 P: 170.0 R: 12.98 P: 189.1 R: 2.55 P: 286    R: 12.22 P: 170.0 R: 12.98 P: 189.1 R: 2.55 P: 286   
Levels: R: 12.22 P: 170.0 R: 12.98 P: 189.1 R: 2.55 P: 286

I want the level to be ordered according to the first number in the factor in the example, i.e., in the order of 2.55, 12.22 and 12.98

The result will be like below:

## ordered level
FC 
Levels: R: 2.55 P: 286 R: 12.22 P: 170.0 R: 12.98 P: 189.1

What I am thinking to extract the first number in the factor vector, and then order the factor.

fistNum <- read.table(text = levels(FC))[[2]]

fistNum 
[1] 12.22 12.98  2.55

I then don't know how to continue. Thanks for your help.

CodePudding user response:

Something like this ?

levels(FC) <- FC[order(readr::parse_number(as.character(levels(FC))))]
levels(FC)

#[1] "R: 2.55 P: 286"    "R: 12.22 P: 170.0" "R: 12.98 P: 189.1"

readr::parse_number would extract the first number from the vector FC, we order those numbers and assign the levels

CodePudding user response:

In base

FC <- factor(c("R: 12.22 P: 170.0", "R: 12.98 P: 189.1", "R: 2.55 P: 286", "R: 12.22 P: 170.0", "R: 12.98 P: 189.1", "R: 2.55 P: 286"))

# Coherce to character for gsub
cc <- paste(FC)
cc
#> [1] "R: 12.22 P: 170.0" "R: 12.98 P: 189.1" "R: 2.55 P: 286"   
#> [4] "R: 12.22 P: 170.0" "R: 12.98 P: 189.1" "R: 2.55 P: 286"

# Get first value in each string
fv <- gsub(pattern = ".*\\s([0-9.]*)\\s.*", replacement = "\\1", x = cc)
fv
#> [1] "12.22" "12.98" "2.55"  "12.22" "12.98" "2.55"

df <- data.frame(cbind(cc, fv))
df
#>                  cc    fv
#> 1 R: 12.22 P: 170.0 12.22
#> 2 R: 12.98 P: 189.1 12.98
#> 3    R: 2.55 P: 286  2.55
#> 4 R: 12.22 P: 170.0 12.22
#> 5 R: 12.98 P: 189.1 12.98
#> 6    R: 2.55 P: 286  2.55

FC <- factor(FC, levels = unique(df[order(as.numeric(df$fv)),"cc"]))
FC
#> [1] R: 12.22 P: 170.0 R: 12.98 P: 189.1 R: 2.55 P: 286    R: 12.22 P: 170.0
#> [5] R: 12.98 P: 189.1 R: 2.55 P: 286   
#> Levels: R: 2.55 P: 286 R: 12.22 P: 170.0 R: 12.98 P: 189.1

CodePudding user response:

Thanks @Ronak Shah. Following your answer, I have added another answer with base R.

levels(FC) <- levels(FC)[order(read.table(text = levels(FC), fill = TRUE)[[2]])]

CodePudding user response:

We could use fct_relevel

library(forcats)
FC2 <- fct_relevel(FC, gtools::mixedsort(levels(FC)))
levels(FC2)
[1] "R: 2.55 P: 286"    "R: 12.22 P: 170.0" "R: 12.98 P: 189.1"
  • Related