在数据帧的每一行上应用两列函数

时间:2018-01-15 12:54:32

标签: r

我有一个函数返回两个字符串中最长的公共子字符串:

longest.substring <-function(a,b)
{
  A <- strsplit(a, "")[[1]]
  B <- strsplit(b, "")[[1]]

  L <- matrix(0, length(A), length(B))
  ones <- which(outer(A, B, "=="), arr.ind = TRUE)
  ones <- ones[order(ones[, 1]), ]
  if(length(ones)!=0){
    for(i in 1:nrow(ones)) {
      v <- ones[i, , drop = FALSE]
      L[v] <- ifelse(any(v == 1), 1, L[v - 1] + 1)
    }
    paste0(A[(-max(L) + 1):0 + which(L == max(L), arr.ind = TRUE)[1]], collapse = "")
  }
}

longest.substring("hello world","hella old") #returns "hell"
longest.substring("abc","def") #returns nothing

最初在Identify a common pattern中找到,我添加了if子句来处理根本没有子串匹配的字符串。它的工作正常,如代码中的示例所示,但我将问题应用于我的数据集时遇到了问题。对于它的每一行,我想在两列的值上使用此函数,并将结果输入第三列。我试了几次,例如:

table1$LCS <- mapply(longest.substring, table1$col1, table1$col2)
table1$LCS <- apply(table1[,c("col1","col2")], 1, function(x)
                    longest.substring(x["col1"],x["col2"]))

两种方式(我使用mapply在这些列之间运行adist并且工作正常)返回错误:

Error in 1:nrow(ones) : argument of length 0

从我在两个字符串上运行它的测试,这正是我添加if之前发生的事情,所以函数'省略'这个子句并尝试运行导致错误的for。 / p>

另外我想注意我的数据集非常大(几千行),所以我认为for循环需要很长时间才能完成。

编辑也使for循环,但它返回与上面相同的错误。

for (i in 1:nrow(Adresy_baza_match)){
  Adresy_baza_match[i,"LCS"] <- longest.substring(Adresy_baza_match[i,4], Adresy_baza_match[i,5])
}

编辑我设法隔离哪一行导致错误:

            a                          b
921 BRUSKIEGO                  PLATYNOWA
922 BRUSKIEGO BPAHIERONIMAROZRAŻEWSKIEGO
923 BRUSKIEGO     BPAKONSTANTYNADOMINIKA

第一行似乎导致它:

x <-longest.substring("BRUSKIEGO", "PLATYNOWA")

在这种情况下(逐行length(ones)运行功能代码为2,而nrow(ones)返回NULL,每次只有一个匹配时,我会发生其他尝试substring,它由一个char组成。

2 个答案:

答案 0 :(得分:1)

有几点:

  1. 问题代码中的这一行:

    ones <- ones[order(ones[, 1]), ] 
    

    应该是:

    ones <- ones[order(ones[, 1]), , drop = FALSE ] 
    
  2. 定义longest.substring.vec,类似于longest.substring,但它接受 vector ab,而不仅仅是标量< / em>的。它还强制其对字符的参数,并用NA替换NULL,以确保结果是字符向量而不是列表。现在试试这个:

    longest.substring.vec <- function(a, b, default = NA_character_, 
             USE.NAMES = FALSE) {
      a <- as.character(a)
      b <- as.character(b)
      m <- mapply(longest.substring, a, b, USE.NAMES = USE.NAMES)
      m[lengths(m) == 0] <- default
      unlist(m)
    }
    
  3. 测试这两项变化:

    tab <- data.frame(a = c("hello, world", "abc"), b = c("hella old", "def"))
    transform(tab, c = longest.substring.vec(a, b))
    ##              a         b    c
    ## 1 hello, world hella old hell
    ## 2          abc       def <NA>
    

    <强>更新

    添加了第1点。重新排列的演示文稿。

答案 1 :(得分:1)

GrpString 包提供了一个更简单、更强大的解决方案。

s <- c("hello world","hello old", "hello")

GrpString::CommonPatt(s) %>% 
filter(Freq_str == length(s)) %>% filter(Length == max(Length)) %>% 
select(Pattern) %>% unlist(use.names = F)

检查 GrpString::CommonPatt(s) 的输出以获取有关常见模式的更多信息