【问题标题】:In R, compare two lists of strings, find parts of each element of the first list on the second在R中,比较两个字符串列表,在第二个列表中找到第一个列表的每个元素的部分
【发布时间】:2016-05-15 14:25:09
【问题描述】:

注意:我已更新问题以反映数据中的特定模式。

假设我有两个向量。

   names_data <- c('A', 'B', 'C', 'D', 'E', 'F')
   levels_selected <- c('A1','A3', 'Blow', 'Bhigh', 'D(4.88e+03,9.18+e+04]', 'F')

我想知道如何获取一个向量、一个数据框、一个列表或其他任何东西,以检查级别向量并返回选择了哪些变量的哪些级别。有句话说:

    A: 1, 3
    B: low, high
    D: (4.88e+03,9.18e+04]

最终,有一个数据框X,其中names_data = names(data)levels_selected 是每个变量中的部分级别,但不是全部级别。最后,我想要做的是使用model.matrix 制作一个矩阵(例如,一个随机森林),我只想在levels_selected 中包含变量和级别。有没有直接的方法?

【问题讨论】:

  • 你控制levels_selected向量的结构吗? IE。它总是格式化为“名称+级别”吗?
  • 是的。它总是这样格式化,中间没有空格、连字符或其他任何东西。
  • 新结构也适用于我的解决方案

标签: r subset


【解决方案1】:

我们可以在保留“levels_selected”('grp')中包含“names_data”的子字符串后创建一个分组变量,split使用'grp'去除前缀的子字符串以获得list

grp <- sub(paste0("^(", paste(names_data, collapse="|"), ").*"), "\\1", levels_selected)
value <- gsub(paste(names_data, collapse="|"), "", 
               levels_selected)
lst <- split(value, grp)
lst
#$A
#[1] "1" "3"

#$B
#[1] "low"  "high"

#$D
#[1] "x"

如果我们的意思是这样的

library(qdapTools)
mtabulate(lst)
#  1 3 high low x
#A 1 1    0   0 0
#B 0 0    1   1 0
#D 0 0    0   0 1

或者另一个选项是使用strsplit

d1 <- as.data.frame(do.call(rbind, strsplit(levels_selected,
      paste0("(?<=(", paste(names_data, collapse="|"), "))"), 
             perl=TRUE)), stringsAsFactors=FALSE)
aggregate(V2~V1, d1, FUN= toString)
#  V1        V2
#1  A      1, 3
#2  B low, high
#3  D         x

model.matrix 可能是

model.matrix(~V1+V2-1, d1)

更新

通过使用 OP 的新示例

d1 <- as.data.frame(do.call(rbind, strsplit(levels_selected,
  paste0("(?<=(", paste(names_data, collapse="|"), "))"), 
         perl=TRUE)), stringsAsFactors=FALSE)
split(d1$V2, d1$V1) 
#$A
#[1] "1" "3"

#$B
#[1] "low"  "high"

#$D
#[1] "(4.88e+03,9.18+e+04]"

它也适用于第一种方法。

更新2

如果'names_data'中的元素没有字符,我们可以将它们过滤掉

lst <- strsplit(levels_selected, paste0("(?<=(", paste(names_data, 
            collapse="|"), "))"), perl = TRUE)
d2 <-  as.data.frame(do.call(rbind,lst[lengths(lst)==2]), stringsAsFactors=FALSE)
split(d2$V2, d2$V1)
#$A
#[1] "1" "3"

#$B
#[1] "low"  "high"

#$D
#[1] "(4.88e+03,9.18+e+04]"

【讨论】:

  • 然后,有没有办法只使用这些级别来获得模型矩阵?
  • @MathUser 我更新了一个可能的结果。这是你想要的吗?
  • 它给了我一个错误,它说'invalid split pattern'。
  • @MathUser 我只是使用你的例子,它没有给出任何错误
  • 是的,这正是我想要的。但是,它在真实数据集中不起作用:/
【解决方案2】:

一个选项返回一个列表,其中包含存储在每个对应名称下的向量作为向量:

> setNames(lapply(names_data, function(x) gsub(x, "", levels_selected[grepl(x, levels_selected)])), names_data)
$A
[1] "1" "3"

$B
[1] "low"  "high"

$C
character(0)

$D
[1] "x"

$E
character(0)

【讨论】:

    【解决方案3】:

    所以这是我从 regexpr 帮助示例中扩展的一个方便的小功能,使用 perl 风格的正则表达式

    parseAll <- function(data, pattern) {
    
      result <- gregexpr(pattern, data, perl = TRUE)
      do.call(rbind,lapply(seq_along(data), function(i) {
      if(any(result[[i]] == -1)) return("")
      st <- data.frame(attr(result[[i]], "capture.start"))
      le <- data.frame(attr(result[[i]], "capture.length") - 1)
    
      mapply(function(start,leng) substring(data[i], start, start + leng), st, le)
    
    }))
    }
    

    编辑:它被扩展了,因为它会找到多个匹配的模式,让您可以查找每行多个模式。所以像这样的模式:"(?&lt;first&gt;[[:upper:]][[:lower:]]+) (?&lt;last&gt;[[:upper:]][[:lower:]]+)"(来自原始 regexpr 帮助)会在每个字符串中找到该模式的所有实例,而不仅仅是一个。

    假设我的数据如下所示:

    dat <- c('A1','A2','A3','B3')
    

    然后我可以通过以下方式搜索此数据 parseAll(z,'A(?&lt;A&gt;.*)|B(?&lt;B&gt;.*)') 获取选定级别的 data.frame:

    parseAll(dat,'A(?&lt;A&gt;.*)|B(?&lt;B&gt;.*)')

         A   B  
    [1,] "1"  "" 
    [2,] "2"  ""
    [3,] "3"  "" 
    [4,] ""   "3" 
    

    每个级别都有哪些选择(尽管这可能对您没有用),我也可以通过您的向量以编程方式生成这些模式:

    pattern &lt;- paste(paste0(names_data,'(?&lt;',names_data,'&gt;.*)'),collapse = '|')

    那么您选择的级别是每列的唯一元素,(它在 data.frame 中,因此转换为列表很容易)

    这是我的万能工具,希望能派上用场

    【讨论】:

    • regexpr 可以用来做同样的事情,(但我有使用 gregreexpr 的函数)他想要在某些数据结构中被某些模式分解的第二部分的级别。跨度>
    • 我认为你是对的,这不仅仅是针对这个问题的工具,而是针对问题类别“如果我将数据存储在连接字符串中,我如何将其提取到R中有用的数据结构”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-28
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 2012-08-18
    相关资源
    最近更新 更多