【问题标题】:Ordering a complex string vector in order to obtain a ordered factor对复杂的字符串向量进行排序以获得有序因子
【发布时间】:2016-02-04 23:20:26
【问题描述】:

我正在使用一个字符串向量,其结构对应于以下结构:

messy_vec <- c("0 - 9","100 - 150","21 - abc","50 - 56","70abc - 80")

我希望将此向量的一个类更改为因素,将根据第一个数字对级别进行排序。代码:

messy_vec_fac <- as.factor(messy_vec)

会产生

> messy_vec_fac
[1] 0 - 9      100 - 150  21 - abc   50 - 56    70abc - 80
Levels: 0 - 9 100 - 150 21 - abc 50 - 56 70abc - 80

而我有兴趣获得特征向量:

[1] 0-9 100 - 150 21 - abc 50 - 56 70abc - 80

级别:0 - 9 21 - abc 50 - 56 70abc - 80 100 - 150

如图所示,级别的顺序与顺序相对应:

0 21 50 70 100

这是从混乱向量的元素派生的第一个数字。

支点

这对于所寻求的解决方案并不重要,但如果所提出的解决方案不假设向量元素的第一部分中的最大位数,那将是很好的。可能会出现以下值:

  • 8787abc - 89898 deff - 在这种情况下,应该使用值 8787 来断言订单
  • 001 def - 1111 OHMG - 在这种情况下,值 1 应该用于断言订单
  • 可以安全地假设所有向量元素都有-字符串:[[:space:]]-[[:space:]]
  • 出现重复值

编辑

根据 CathG 的非常有用的建议,我正在尝试将此解决方案填充到更大的 dplyr 语法中

# ... %>%
  mutate(very_needed_factor= factor(messy_vec,
                                      levels = messy_vec[
                                        order(
                                          as.numeric(
                                            sub("(\\d+)[^\\d]* - .*", "\\1",
                                                messy_vec)))]))
# %>% ...

但我不断收到以下错误:

Warning messages:
1: In order(as.numeric(sub("(\\d+)[^\\d]* - .*", "\\1", c("12-14",  :
  NAs introduced by coercion
2: In `levels<-`(`*tmp*`, value = if (nl == nL) as.character(labels) else paste0(labels,  :
  duplicated levels in factors are deprecated

【问题讨论】:

  • 相对于您的编辑,也许可以尝试使用unique 来定义级别(例如在我的 A 的 NB 部分)?至少对于错误的第二点来说,这似乎是问题所在。对于第一点,我们可能需要您的实际向量,以便我们可以重现错误,因为您提供的向量没有给出...(如果我复制一个值并且不使用唯一的,我会收到重复级别的警告不过)
  • 在您的第一条警告消息中,您似乎有一个值,连字符周围没有空格。如果是这样,那么我的正则表达式无法正确捕获数字,而只需修改正则表达式以抑制空格,它应该可以工作
  • @CathG 你是对的,为了简洁和可重复性,我创建的 messy_vector 并不反映实际数据的确切性质。但正如您所说,解决方法非常简单。

标签: r string class sorting vector


【解决方案1】:

如果我正确理解了您想要做什么,您可以使用sub 捕获每个字符串中出现的第一个数字,并将它们转换为数字,然后用于在factor 调用中对级别进行排序。

num_vec <- as.numeric(sub("(\\d+)[^\\d]* - .*", "\\1", messy_vec))
messy_vec_fac <- factor(messy_vec, levels=messy_vec[order(num_vec)])

messy_vec_fac
#[1] 0 - 9      100 - 150  21 - abc   50 - 56    70abc - 80
#Levels: 0 - 9 21 - abc 50 - 56 70abc - 80 100 - 150

注意:如果出现重复值,您可以在factor 调用中执行levels=unique(messy_vec[order(num_vec)])

【讨论】:

  • 非常感谢您的及时回复并提出了非常有用的解决方案。
【解决方案2】:

这是另一个解决方案

library(magrittr)    
messy_vec <- c("0 - 9","100 - 150","21 - abc","50 - 56","70abc - 80")
ints <- strsplit(messy_vec, "-") %>% 
  unlist() %>% 
  gsub(pattern = "([[:space:]]|[[:alpha:]])*", replacement = "") %>% 
  as.integer() %>% 
  matrix(nrow = 2)
factor(messy_vec, levels = messy_vec[order(ints[1, ], ints[2, ])])

【讨论】:

    猜你喜欢
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-29
    • 2019-03-31
    • 2019-02-03
    相关资源
    最近更新 更多