【问题标题】:Replacement has 0 rows, data has 25 error替换有0行,数据有25个错误
【发布时间】:2020-12-26 15:36:04
【问题描述】:

我正在尝试制作一个包含 25 个不同密码的列表,以检查另一个包含 50 个密码的列表,然后返回匹配项。这是一个关于密码的大学项目。这个想法是 25 个最常用密码的列表,我希望 R 告诉我 50 个密码中的哪一个与最常见的 25 个匹配。但是我一直收到以下错误:

Error in $<-.data.frame(*tmp*, "Percent", value = character(0)) :
replacement has 0 rows, data has 25

我正在使用以下代码

makeCounts <- function(x) {
  return(x=list("count"=sum(grepl(x, Final_DF$pswd, ignore.case=TRUE))))  
}

#creates a local variable named tmp which is removed afterwards
printCounts <- function(ct) {
  tmp <- data.frame(Term=names(ct), Count=as.numeric(unlist(ct)))
  tmp$Percent <- sprintf("%3.2f%%", ((tmp$Count / nrow(Final_DF$Pswd) * 100)))
  print(tmp[order(-tmp$Count),], row.names=FALSE)
}

# create top 25 mostly commonly used pswds

worst.pass <- c("password", "123456", "12345678", "qwerty", "abc123", 
                "monkey", "1234567", "Qwertyuiop", "123", "dragon", 
                "000000", "1111111", "iloveyou", "1234", "12345", 
                "1234567890", "1q2w3e4r5t", "ashely", "shadow", "123123", 
                "654321", "superman", "sunshine", "tinkle", "football")

worst.ct <- sapply(worst.pass, makeCounts, simplify=FALSE)
printCounts(worst.ct)

包含我的 50 个密码的数据包含在我的数据框 Final_DF$Pswd 中,如下所示

> Final_DF$Pswd
 [1] "monkey"       "iloveyou"     "dragon"       "jbI2pnK$xi"   "password"     "computer"     "!qessw"      
 [8] "tUNh&SSm6!"   "sunshine"     "wYrUeWV"      "superman"     "samsung"      "utoXGe6$"     "master"      
[15] "wjZC&OvXX"    "0R1cNTm9sGir" "Fbuu2bs89?"   "pokemon"      "secret"       "x&W1TjO59"    "buster"      
[22] "purple"       "shine"        "flower"       "marina"       "Tg%OQT$0"     "SbDUV&nOX"    "peanut"      
[29] "angel"        "?1LOEc4Zfk"   "computer"     "spiderman"    "nothing"      "$M6LgmQgv$"   "orange"      
[36] "knight"       "american"     "outback"      "TfuRpt3PiZ"   "air"          "surf"         "lEi2a$$eyz"  
[43] "date"         "V$683rx$p"    "newcastle"    "estate"       "foxy"         "ginger"       "coffee"      
[50] "legs" 

当我运行printCounts(worst.ct)读取时显示错误的回溯

 Error in `$<-.data.frame`(`*tmp*`, "Percent", value = character(0)) : 
  replacement has 0 rows, data has 25 
4.
stop(sprintf(ngettext(N, "replacement has %d row, data has %d", 
    "replacement has %d rows, data has %d"), N, nrows), domain = NA) 
3.
`$<-.data.frame`(`*tmp*`, "Percent", value = character(0)) 
2.
`$<-`(`*tmp*`, "Percent", value = character(0)) 
1.
printCounts(worst.ct) 

我已经阅读了一些论坛帖子,但我不确定这是否与 NA 值有关?我是 R 新手,一直在摸索这个问题。

谁能告诉我哪里出错了?

> dput(Final_DF)
structure(list(gender = c("female", "male", "male", "female", 
"female", "male", "male", "male", "male", "female", "male", "male", 
"female", "female", "female", "female", "male", "female", "male", 
"male", "female", "female", "female", "female", "female", "female", 
"male", "female", "female", "female", "female", "female", "female", 
"female", "male", "male", "female", "female", "male", "female", 
"female", "male", "female", "female", "male", "male", "male", 
"male", "male", "male"), age = structure(c(47L, 43L, 65L, 24L, 
44L, 60L, 26L, 25L, 62L, 23L, 44L, 61L, 27L, 47L, 18L, 23L, 34L, 
77L, 71L, 19L, 64L, 61L, 22L, 55L, 45L, 29L, 21L, 64L, 43L, 20L, 
32L, 55L, 68L, 21L, 81L, 43L, 63L, 72L, 38L, 20L, 66L, 39L, 64L, 
20L, 73L, 21L, 53L, 75L, 69L, 82L), class = c("variable", "integer"
), varname = "Age"), web_browser = structure(c(1L, 1L, 4L, 1L, 
3L, 3L, 2L, 1L, 4L, 1L, 1L, 1L, 3L, 4L, 1L, 2L, 1L, 3L, 3L, 2L, 
1L, 1L, 1L, 3L, 4L, 3L, 4L, 4L, 1L, 2L, 1L, 1L, 3L, 1L, 1L, 2L, 
1L, 2L, 3L, 4L, 2L, 3L, 1L, 1L, 1L, 1L, 3L, 3L, 4L, 1L), .Label = c("Chrome", 
"Internet Explorer", "Firefox", "Netscape"), class = c("variable", 
"factor"), varname = "Browser"), Pswd = c("monkey", "iloveyou", 
"dragon", "jbI2pnK$xi", "password", "computer", "!qessw", "tUNh&SSm6!", 
"sunshine", "wYrUeWV", "superman", "samsung", "utoXGe6$", "master", 
"wjZC&OvXX", "0R1cNTm9sGir", "Fbuu2bs89?", "pokemon", "secret", 
"x&W1TjO59", "buster", "purple", "shine", "flower", "marina", 
"Tg%OQT$0", "SbDUV&nOX", "peanut", "angel", "?1LOEc4Zfk", "computer", 
"spiderman", "nothing", "$M6LgmQgv$", "orange", "knight", "american", 
"outback", "TfuRpt3PiZ", "air", "surf", "lEi2a$$eyz", "date", 
"V$683rx$p", "newcastle", "estate", "foxy", "ginger", "coffee", 
"legs"), pswd_length = c(6L, 8L, 6L, 10L, 8L, 8L, 6L, 10L, 8L, 
7L, 8L, 7L, 8L, 6L, 9L, 12L, 10L, 7L, 6L, 9L, 6L, 6L, 5L, 6L, 
6L, 8L, 9L, 6L, 5L, 10L, 8L, 9L, 7L, 10L, 6L, 6L, 8L, 7L, 10L, 
3L, 4L, 10L, 4L, 9L, 9L, 6L, 4L, 6L, 6L, 4L), last.num = c(NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, 9, NA, NA, NA, NA, NA, 0, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA)), row.names = c(NA, -50L), class = "data.frame")

【问题讨论】:

  • 你应该使用dput提供Final_DF,阅读:stackoverflow.com/a/5963610/6574038
  • 可能的重复对象,[r] replacement has 0 rows
  • 应该 nrow(Final_DF$Pswd) 而不是 nrow(Final_DF)?如果它是一个简单的列,那么它保证返回NULL
  • 顺便说一句,让你的函数依赖一个既没有在函数内部定义也没有传递给函数的外部变量是一个坏主意:它破坏了可重复性,并且会使故障排除变得困难。一个快速的选择是向printCounts(ct, finaldf) 添加一个参数并使用printCounts(worst.ct, Final_DF) 调用它。
  • @r2evans 的不同之处在于它打印了术语、计数和百分比,但它无法识别匹配项,所有计数均显示为 0

标签: r


【解决方案1】:

您的函数有几处看起来有问题。

  1. makeCounts 引用 pswd,但 Final_DF 具有 Pswdpswd_length。 R 正在做部分匹配,我猜它不是你想要的。让我们证明它在使用什么,首先通过设置一个选项[1]:

    options(warnPartialMatchDollar = TRUE) # see ?options
    worst.ct <- sapply(worst.pass, makeCounts, simplify=FALSE)
    # Warning in Final_DF$pswd : partial match of 'pswd' to 'pswd_length'
    # Warning: partial match of 'pswd' to 'pswd_length'
    # Warning: partial match of 'pswd' to 'pswd_length'
    # Warning: partial match of 'pswd' to 'pswd_length'
    # Warning: partial match of 'pswd' to 'pswd_length'
    ### ...repeated...
    

    更糟糕的是,如果您查看此变量(解决问题的一部分是检查您正在制作和使用的变量),您会发现它实际上是空的/无用的,其中所有值都是 0:

    str(worst.ct)
    # List of 25
    #  $ password  :List of 1
    #   ..$ count: int 0
    #  $ 123456    :List of 1
    #   ..$ count: int 0
    #  $ 12345678  :List of 1
    #   ..$ count: int 0
    #  $ qwerty    :List of 1
    #   ..$ count: int 0
    ### ...truncated...
    

    如果您更改函数以使用正确的列名,它不会提供此类警告,并且它确实包含一些非零元素:

    makeCounts <- function(x) {
      return(x=list("count"=sum(grepl(x, Final_DF$Pswd, ignore.case=TRUE))))  
    }
    table(unlist(worst.ct))
    #  0  1 
    # 19  6 
    
    str(worst.ct)
    # List of 25
    #  $ password  :List of 1
    #   ..$ count: int 1
    #  $ 123456    :List of 1
    #   ..$ count: int 0
    #  $ 12345678  :List of 1
    #   ..$ count: int 0
    #  $ qwerty    :List of 1
    #   ..$ count: int 0
    ### ...truncated...
    
  2. 在你的printCounts 函数中,你引用了nrow(Final_DF$Pswd),它总是会产生NULL。你试过吗?

    nrow(Final_DF$Pswd)
    # NULL
    nrow(Final_DF)
    # [1] 50
    

    相反,将该行重写为

      tmp$Percent <- sprintf("%3.2f%%", ((tmp$Count / nrow(Final_DF) * 100)))
    
  3. 不是语法错误,但是你的函数依赖于一个既没有在其中定义也没有传递给它的变量是不好的做法:这意味着当向它传递相同的参数时,函数的行为可能会有所不同,这会破坏可重复性(并且这会使故障排除变得相当困难)。

    我建议将Final_DF 作为函数的参数,并且每次都传递它。

    printCounts <- function(ct, Final_DF) {
      tmp <- data.frame(Term=names(ct), Count=as.numeric(unlist(ct)))
      tmp$Percent <- sprintf("%3.2f%%", ((tmp$Count / nrow(Final_DF) * 100)))
      print(tmp[order(-tmp$Count),], row.names=FALSE)
    }
    
    printCounts(worst.ct)
    # Error in nrow(Final_DF) : argument "Final_DF" is missing, with no default
    
    printCounts(worst.ct, Final_DF) # no error here
    

    对于这种情况,我建议您不要为其提供默认值。这也使您能够使用具有不同“最终”密码帧的相同功能,以防您正在测试(单元测试)或测试(训练/测试抽样)或测试(故障排除)。

在这些更改之后,我得到了这个:

printCounts(worst.ct, Final_DF)
#        Term Count Percent
#    password     1   2.00%
#      monkey     1   2.00%
#      dragon     1   2.00%
#    iloveyou     1   2.00%
#    superman     1   2.00%
#    sunshine     1   2.00%
#      123456     0   0.00%
#    12345678     0   0.00%
#      qwerty     0   0.00%
#      abc123     0   0.00%
#     1234567     0   0.00%
#  Qwertyuiop     0   0.00%
#         123     0   0.00%
#      000000     0   0.00%
#     1111111     0   0.00%
#        1234     0   0.00%
#       12345     0   0.00%
#  1234567890     0   0.00%
#  1q2w3e4r5t     0   0.00%
#      ashely     0   0.00%
#      shadow     0   0.00%
#      123123     0   0.00%
#      654321     0   0.00%
#      tinkle     0   0.00%
#    football     0   0.00%

注意:

  1. 我在我的~/.Rprofile (以及任何特定于项目的.Rprofile 初始化文件)中设置了options(warnPartialMatchDollar=TRUE, warnPartialMatchAttr=TRUE) 正是因为这个原因:$ 静默 进行部分匹配,这可以会很成问题。有了警告,至少您可以看到 R 在后台推断什么。还有第三个选项,warnPartialMatchArgs,具有相同的意图......但是 waaaaaaaaaay 太多的包作者无意中依赖于这种行为,因此缺乏时间/能力来修复它们,我选择了消音噪音制造者。

    特别是如果这种部分匹配行为让您感到惊讶,我强烈建议您自己设置前两个选项。在最好的情况下,它不会产生任何警告,并且您可以放心地知道您正在采取措施来生成更具弹性的代码;在最坏的情况下,它很吵,你最终会厌倦噪音并修复惰性代码。

    请参阅?options 了解这三个以及许多其他可用选项。 (包也可以设置自己的选项;选项在概念上类似于 Windows 的注册表,无论好坏,因为它对 R 来说是全局的,并且可以具有任意键和值。)

【讨论】:

  • 谢谢,您的更改有效,总而言之,以检查我的理解,这完全是因为在一个 DF 中重复 pswd 名称? `options(warnPartialMatchDollar = TRUE)' 这行代码是做什么的,是不是帮助我们定位问题?
  • (1) 您的函数中有两个错误。 (2) 该选项集有助于确定其中一个问题出在哪里,当您逐行浏览代码时,另一个错误很明显。要了解有关该选项的更多信息,请参阅 ?options 并搜索 warnPartialMatchDollar;我可以在这里复制/粘贴,但最好找到权威文档。
【解决方案2】:

如果您只想检查(一组)密码是否在一组错误密码中,您可以使用

Final_DF$Pswd %in% worst.pass

这将为您提供TRUEFALSE 的向量。您可以运行 sum(Final_DF$Pswd %in% worst.pass) 来获取错误密码匹配的总数,或者运行 table(Final_DF$Pswd[Final_DF$Pswd %in% worst.pass]) 来快速了解匹配情况。

但是,如果您的意图是检查不断添加密码的集合(我猜这是意图,因为您制作了函数),以下可能有用:

result <- c()
for (i in 1:length(Final_DF$Pswd)) {
    if (Final_DF$Pswd[i] %in% worst.pass) {
        result[i] <- which(worst.pass == Final_DF$Pswd[i])
    } else
        result[i] <- NA
}
table(worst.pass[result[!is.na(result)]])

结果是一个包含匹配计数的表格。在你的情况下,

  dragon iloveyou   monkey password sunshine superman 
       1        1        1        1        1        1 

请注意,对于大量密码循环是不可取的。在这种情况下,整洁的tidyverseapproaches 值得一看。

【讨论】:

    猜你喜欢
    • 2018-04-10
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2015-07-01
    • 2018-05-15
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多