【问题标题】:Extracting nth element from a nested list following strsplit - R从 strsplit - R 之后的嵌套列表中提取第 n 个元素
【发布时间】:2014-09-01 15:18:47
【问题描述】:

我一直试图了解如何更好地处理strsplit 的输出。我经常有这样的数据想要拆分:

mydata <- c("144/4/5", "154/2", "146/3/5", "142", "143/4", "DNB", "90")

#[1] "144/4/5" "154/2"   "146/3/5" "142"     "143/4"   "DNB"     "90"     

拆分后的结果如下:

strsplit(mydata, "/")

#[[1]]
#[1] "144" "4"   "5"  

#[[2]]
#[1] "154" "2"  

#[[3]]
#[1] "146" "3"   "5"  

#[[4]]
#[1] "142"

#[[5]]
#[1] "143" "4"  

#[[6]]
#[1] "DNB"

#[[7]]
#[1] "90"

我从 strsplit 帮助指南中知道不会生成最终的空字符串。因此,根据要拆分的“/”的数量,我的每个结果中都会有 1、2 或 3 个元素

获取第一个元素非常简单:

sapply(strsplit(mydata, "/"), "[[", 1)

#[1] "144" "154" "146" "142" "143" "DNB" "90" 

但是当每个结果中存在这些不相等数量的元素时,我不确定如何获得第二个、第三个...。

sapply(strsplit(mydata, "/"), "[[", 2)

# Error in FUN(X[[4L]], ...) : subscript out of bounds

我希望从一个可行的解决方案中返回,如下:

#[1] "4" "2" "3" "NA" "4" "NA" "NA" 

这是一个相对较小的例子。我可以很容易地对这些数据执行一些 for 循环,但是对于具有 1000 次观察的真实数据来运行 strsplit 以及由此产生的数十个元素,我希望找到一个更通用的解决方案。

【问题讨论】:

  • 使用 [ 而不是 [[ 似乎有效
  • @alexis_laz 您应该将此作为答案。我在help("[") 中找不到这个。

标签: r sapply strsplit


【解决方案1】:

(至少关于一维向量)[ 似乎在 "i > length(x)" 时返回 NA[[ 返回错误。

x = runif(5)
x[6]
#[1] NA
x[[6]]
#Error in x[[6]] : subscript out of bounds

稍微挖掘一下,do_subset_dflt(即[)调用ExtractSubset,我们注意到当想要的索引(“ii”)是“>长度(x)”时返回NA(稍作修改)要干净):

if(0 <= ii && ii < nx && ii != NA_INTEGER)
    result[i] = x[ii];
else
    result[i] = NA_INTEGER;

另一方面,do_subset2_dflt(即[[)如果想要的索引(“偏移量”)是“>长度(x)”(修改一点以保持干净),则会返回错误:

if(offset < 0 || offset >= xlength(x)) {
    if(offset < 0 && (isNewList(x)) ...
    else errorcall(call, R_MSG_subs_o_b);
}

在哪里#define R_MSG_subs_o_b _("subscript out of bounds")

(我不确定上面的代码 sn-ps,但根据它们的返回,它们似乎确实相关)

【讨论】:

    【解决方案2】:

    试试这个:

    > read.table(text = mydata, sep = "/", as.is = TRUE, fill = TRUE)
       V1 V2 V3
    1 144  4  5
    2 154  2 NA
    3 146  3  5
    4 142 NA NA
    5 143  4 NA
    6 DNB NA NA
    7  90 NA NA
    

    如果您想将 DNB 视为 NA,请添加参数 na.strings="DNB"

    如果你真的想使用strsplit,那么试试这个:

    > do.call(rbind, lapply(strsplit(mydata, "/"), function(x) head(c(x,NA,NA), 3)))
         [,1]  [,2] [,3]
    [1,] "144" "4"  "5" 
    [2,] "154" "2"  NA  
    [3,] "146" "3"  "5" 
    [4,] "142" NA   NA  
    [5,] "143" "4"  NA  
    [6,] "DNB" NA   NA  
    [7,] "90"  NA   NA  
    

    注意:使用 alexis_laz 的观察,如果 i 不在 1:length(x) 中,则 x[i] 返回 NA 上面的最后一行代码可以简化为:

    t(sapply(strsplit(mydata, "/"), "[", 1:3))
    

    【讨论】:

    • 关于你的第二种方法:使用length&lt;- 应该是更可取的。 nmax &lt;- max(sapply(mysplitdata, length)); mysplitdata &lt;- lapply(mysplitdata, "length&lt;-", value=nmax)
    【解决方案3】:

    你可以使用regex(如果允许的话)

     library(stringr)
     str_extract(mydata , perl("(?<=\\d/)\\d+"))
     #[1] "4" "2" "3" NA  "4" NA  NA 
     str_extract(mydata , perl("(?<=/\\d/)\\d+"))
    #[1] "5" NA  "5" NA  NA  NA  NA 
    

    【讨论】:

      【解决方案4】:

      您可以在sapply 内分配长度,从而导致NA 的当前长度比分配的长度短。

      s <- strsplit(mydata, "/")
      sapply(s, function(x) { length(x) <- 3; x[2] })
      # [1] "4" "2" "3" NA  "4" NA  NA 
      

      然后您可以使用mapply 添加第二个索引参数

      m <- max(sapply(s, length))
      mapply(function(x, y, z) { length(x) <- z; x[y] }, s, 2, m)
      # [1] "4" "2" "3" NA  "4" NA  NA 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-22
        • 2018-02-07
        • 1970-01-01
        • 2011-03-19
        • 1970-01-01
        相关资源
        最近更新 更多