【问题标题】:Subset a dataframe using a logical vector with $使用带有 $ 的逻辑向量对数据帧进行子集
【发布时间】:2018-09-06 06:27:35
【问题描述】:

我在理解 R 中的 data.frame 子集时 $ 符号的使用原因行为都遇到了困难。提供了以下示例在我正在上的初学者课程中(不是现场教授,所以不能在那里问):

temp_mat <- matrix(1:9, nrow=3)
colnames(temp_mat) <- c('a', 'b', 'c')
temp_df <- data.frame(temp_mat)

调用temp_df 显然输出:

  a b c
1 1 4 7
2 2 5 8
3 3 6 9

课程中给出的例子是:

temp_df[temp_df$c < 10]

哪些输出:

  a b c
1 1 4 7
2 2 5 8
3 3 6 9

使用原因问题:课程指出$用于部分匹配,x$yx[["y", exact=FALSE]]的完全替代。为什么我们要在这里使用部分匹配运算符?我们使用它是因为我们确定在我们的temp_df 中没有其他类似于“c”的列可能会被错误地拾取吗?此外,如何衡量部分匹配?至少 % 的字符匹配或什么?似乎有一个getElement 函数,如果处理具有未知或相似列名的数据集(例如,家庭电话与手机,这些会被视为有效的部分匹配吗?)

行为问题:上面的示例 temp_df[temp_df$c &lt; 10] 似乎是在说“从 temp_df 中返回 c 列小于 10 的元素子集”,并且由于所有 c 列元素都符合条件,因此返回整个数据框。我的解释显然是错误的,因为temp_df[temp_df$c &lt; 9] 返回:

  a b
1 1 4
2 2 5
3 3 6

虽然 c 列中的第 1 行和第 2 行元素确实满足小于 9 的条件,但整个列都被省略了。然后我的问题就变成了双重问题:那个逻辑向量实际上在说/在做什么?以及我将如何编写我对“从 temp_df 中返回 c 列小于 9 的元素子集”的解释并让它返回:

  a b c
1 1 4 7
2 2 5 8

因为在我看来,元素 1 和 2(第 1 行和第 2 行)满足该标准,因为它们的 c 列值小于 9,因此应该返回。

【问题讨论】:

  • 尝试temp_df[temp_df$c &lt; 9, ] 使用逗号来消除索引歧义。
  • 是有道理的,现在它说的是列 c 小于 9 的行。为什么在没有逗号的情况下默认作用于列,尽管 [] 中的行排在第一位?
  • 这是因为考虑数据框的最佳方式是作为一种特殊的list,列名作为键,列内容作为向量值。默认行为基于此原则并删除标记为 FALSE 的键(即列)。
  • 在我看来,任何课程都不应该教temp_df[temp_df$c &lt; 10]这个例子——这样的操作永远不会有用。
  • 我同意弗兰克,现在理解它似乎一点用都没有。作为后续,为什么要使用 $ 运算符呢?如果我有一个具有类似名称列的数据集,我不想让完全匹配的机会留给机会

标签: r dataframe subset


【解决方案1】:

$[[ 都是 extract 运算符,允许按名称提取元素。

OP 提出了一个关于 exact 参数行为的查询。 [[ 运算符的 exact 参数已在 RStudio 中记录为:

控制 [[ 提取时可能的部分匹配 字符向量(对于大多数对象,但请参阅“环境”下)。这 默认是没有部分匹配。值 NA 允许部分匹配,但 发生时发出警告。值 FALSE 允许部分匹配 没有任何警告。

这是什么意思?要了解其行为,让我们将 OP 使用的 data.frame 的 column names 更改为:

names(temp_df) <- c("aa","bb","cc")

#partial name of column will work with exact = FALSE
temp_df[["a", exact = FALSE]]
#[1] 1 2 3
#partial name of column will not work with exact = TRUE
temp_df[["a", exact = TRUE]]
#NULL
temp_df[["a", exact = NA]]
#[1] 1 2 3
#Warning message:
#In .subset2(x, i, exact = exact) : partial match of 'a' to 'aa' 

【讨论】:

  • 这很有帮助,我理解。我的后续问题是:为什么我的导师在我们的案例中选择使用 $?我们知道该列被标记为 c。如果我有一个包含“家庭电话”和“手机”列的数据集,我永远不想使用 $ 并冒险抓住错误的列。我可以看到 $ 的应用程序,我正在寻找不同来源的两个列表之间的共同值(例如,一个说老虎,另一个说孟加拉虎),但我想知道在课程示例中使用 $ 有什么好处。
  • @RichardGolz $ 使用起来非常方便。想想df$Namedf$Amountdf$AccountNumber 这样的情况,在这些情况下使用$ 会更容易。甚至你也可以使用 temp_df$'Home Phone' 之类的东西。
  • 您是说如果数据集有帐号列,df$AccountNumber 会很有用,但您不确定它叫什么?例如,它可以是“Account#”或“Account number”或“AccountNumber”
  • 另外,使用temp_df$"Home Phone",您可能会冒着选择“手机”栏的风险吗?
  • 谢谢 - 它支持部分名称,但如果多个名称符合条件则返回 NULL。抱歉,我是新手。但你帮了很多忙
【解决方案2】:

尝试分步分解操作。

temp_df$c < 9

给出一个向量如下:

[1]  TRUE  TRUE FALSE

当您以您显示的方式传递此向量时: temp_df[c(TRUE, TRUE, FALSE)] 具有对列进行操作的效果。

data.frame 视为一个列表,列名作为键,列内容作为向量值。该操作保留 TRUE 键(即列)并删除 FALSE。

逗号用于将向量标记为行索引。前两行被保留,最后一行被删除。因此,temp_df[c(TRUE, TRUE, FALSE), ] 给出:

  a b c
1 1 4 7
2 2 5 8

【讨论】:

  • 这太棒了 - 我知道我的困惑来自对 data.frame 结构的行为的根本误解,所以这非常有帮助。你对操作的分解是一个很好的教训,它将帮助我回答我自己的问题。谢谢!
猜你喜欢
  • 2021-06-20
  • 2021-03-22
  • 1970-01-01
  • 2018-05-03
  • 1970-01-01
  • 2018-10-09
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
相关资源
最近更新 更多