代码之家  ›  专栏  ›  技术社区  ›  James

如何将r strsplit矢量化?

  •  14
  • James  · 技术社区  · 14 年前

    当创建使用 strsplit ,矢量输入行为不符合要求,以及 sapply 需要使用。这是由于列表输出 纵裂 生产。有没有一种方法使过程向量化——也就是说,函数在列表中为输入的每个元素生成正确的元素?

    例如,要计算字符向量中单词的长度:

    words <- c("a","quick","brown","fox")
    
    > length(strsplit(words,""))
    [1] 4 # The number of words (length of the list)
    
    > length(strsplit(words,"")[[1]])
    [1] 1 # The length of the first word only
    
    > sapply(words,function (x) length(strsplit(x,"")[[1]]))
    a quick brown   fox 
    1     5     5     3 
    # Success, but potentially very slow
    

    理想情况下 length(strsplit(words,"")[[.]]) 哪里 . 被解释为输入向量的相关部分。

    1 回复  |  直到 9 年前
        1
  •  21
  •   Shane    14 年前

    一般来说,您应该尝试使用一个矢量化函数来开始。使用 strsplit 之后会经常需要某种迭代(这会比较慢),所以如果可能的话尽量避免。在您的示例中,应该使用 nchar 而是:

    > nchar(words)
    [1] 1 5 5 3
    

    一般来说,利用 纵裂 返回列表并使用 lapply :

    > as.numeric(lapply(strsplit(words,""), length))
    [1] 1 5 5 3
    

    否则使用 l*ply 家庭职能来源 plyr . 例如:

    > laply(strsplit(words,""), length)
    [1] 1 5 5 3
    

    编辑:

    为了纪念 Bloomsday 我决定用乔伊斯的尤利西斯测试这些方法的性能:

    joyce <- readLines("http://www.gutenberg.org/files/4300/4300-8.txt")
    joyce <- unlist(strsplit(joyce, " "))
    

    既然我有了所有的话,我们就可以计算了:

    > # original version
    > system.time(print(summary(sapply(joyce, function (x) length(strsplit(x,"")[[1]])))))
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0.000   3.000   4.000   4.666   6.000  69.000 
       user  system elapsed 
       2.65    0.03    2.73 
    > # vectorized function
    > system.time(print(summary(nchar(joyce))))
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0.000   3.000   4.000   4.666   6.000  69.000 
       user  system elapsed 
       0.05    0.00    0.04 
    > # with lapply
    > system.time(print(summary(as.numeric(lapply(strsplit(joyce,""), length)))))
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0.000   3.000   4.000   4.666   6.000  69.000 
       user  system elapsed 
        0.8     0.0     0.8 
    > # with laply (from plyr)
    > system.time(print(summary(laply(strsplit(joyce,""), length))))
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0.000   3.000   4.000   4.666   6.000  69.000 
       user  system elapsed 
      17.20    0.05   17.30
    > # with ldply (from plyr)
    > system.time(print(summary(ldply(strsplit(joyce,""), length))))
           V1        
     Min.   : 0.000  
     1st Qu.: 3.000  
     Median : 4.000  
     Mean   : 4.666  
     3rd Qu.: 6.000  
     Max.   :69.000  
       user  system elapsed 
       7.97    0.00    8.03 
    

    矢量化函数和 勒普 比原来快得多 sapply 版本。所有解决方案返回相同的答案(如摘要输出所示)。

    显然是最新版本的 PLYR 速度更快(使用的是稍旧的版本)。

    推荐文章