【问题标题】:subset working in a singular case but not when iterating over a data frame子集在单一情况下工作,但在迭代数据帧时不工作
【发布时间】:2016-10-13 09:11:13
【问题描述】:

我正在尝试对因子水平频率超过 10 的数据框进行子集化。

如果 dogs 是数据框中某个特征的名称:

不起作用:

somevar <- "dogs"
df <- subset(df, with(df, somevar %in% names(which(table(somevar)>=10))))

返回 0 个观测值的 df

有效:

df <- subset(df, with(df, dogs %in% names(which(table(dogs)>=10))))

返回 df 并减少几行,因为那些频率小于 10 的狗的级别已被删除

有什么区别,为什么第二个有效,而前一个无效?

由于我需要遍历数据框中的特征,我需要不起作用的方法来工作!我想将特征名称向量传递给 for 循环

可重现的例子:

vegetables <- c("carrots", "carrots", "carrots", "carrots", "carrots")
animals <- c("cats", "dogs", "dogs", "fish", "cats")
df <- data.frame(vegetables, animals)
df
  vegatables animals
1    carrots    cats
2    carrots    dogs
3    carrots    dogs
4    carrots    fish
5    carrots    cats
> str(df)
'data.frame':   5 obs. of  2 variables:
 $ vegatables: Factor w/ 1 level "carrots": 1 1 1 1 1
 $ animals   : Factor w/ 3 levels "cats","dogs",..: 1 2 2 3 1

我想删除任何因子特征观察频率小于 2 的观察值。在这种情况下,动物因子中水平鱼的频率为 1,因此我希望 df 减少一个观察值:

> test <- subset(df, with(df, animals %in% names(which(table(animals) >= 2))))
> test
  vegatables animals
1    carrots    cats
2    carrots    dogs
3    carrots    dogs
5    carrots    cats

太棒了。

除非我这样做时它不起作用:

categoricals <- names(df)

for ( i in categoricals ) {
  test <- subset(df, with(df, i %in% names(which(table(i) >= 10))))
}

返回一个空的数据框df。我希望它返回的结果与上面的测试 df 完全相同。

类似的:

i <- "animals"
test <- subset(df, with(df, i %in% names(which(table(i) >= 2))))
> test
[1] vegatables animals   
<0 rows> (or 0-length row.names)

我希望最后一个示例能够像我直接在 with 函数中输入动物时那样工作。

【问题讨论】:

  • 我认为问题在于,您在循环中覆盖了df。因此,在第二次迭代中,您的 df 将已经为空。因此将结果存储在其他变量中将是一个解决方案。
  • 嗨@BenjaminMohn,我在问题中添加了更多内容。它甚至不是 for 循环。请参阅上面的“不起作用/起作用”
  • @Hugh 我该怎么办?我尝试 eval(somevar) 代替仅使用 somevar 但没有运气
  • 您能提供示例数据和预期输出吗?目前尚不清楚df 是什么样的。
  • @hugh 是的,我现在已经添加了

标签: r loops subset


【解决方案1】:

请注意,只要其中一个因素低于您所需的阈值,此方法就会从两列中删除行。

vegetables <- c("carrots", "carrots", "carrots", "carrots", "carrots","onion","onion")
animals <- c("cats", "dogs", "dogs", "fish", "cats", "mice","cows")
df <- data.frame(vegetables, animals)

categoricals <- names(df)

for ( i in categoricals ) 
{
  test <- df[df[,i] %in% names(which(table(df[,i]) >= 2)),]
}
test
  vegetables animals
1    carrots    cats
2    carrots    dogs
3    carrots    dogs
5    carrots    cats

【讨论】:

  • 谢谢。为什么我必须使用 df[,i] 出于好奇?
  • 在 R 中提取内容是围绕索引构建的。 df[,i] 利用这个索引函数。 df$vegetables 或 subset(...) 基本相同,但用于交互使用,在任何其他应用程序中都会失败或产生奇怪的行为。
【解决方案2】:

您应该使用每只动物的观察次数创建一个新数据框,将该数据合并到原始数据中,然后以正常方式子集:

vegetables <- c("carrots", "carrots", "carrots", "carrots", "carrots")
animals <- c("cats", "dogs", "dogs", "fish", "cats")
df <- data.frame(vegetables, animals)

library(dplyr)
n_animals <- count(df, animals)

merge(df, n_animals, by = "animals") %>%
  filter(n >= 2)

#   animals vegetables n
# 1    cats    carrots 2
# 2    cats    carrots 2
# 3    dogs    carrots 2
# 4    dogs    carrots 2

【讨论】:

  • 谢谢 Hugh,但我遇到了和以前一样的问题。当它只有一次具有给定的功能名称时,我可以进行子集化。但不是当我在一个循环中遍历一系列特征时:蔬菜 % filter(n >= 2) }
  • 尝试count_ 并查看有关 NSE 的文档。 vignette("nse")
  • 试过 count_() 但没有成功,即使在摆弄引号“”之后也是如此。在我第一次尝试这个时,我也遇到了这个问题。
猜你喜欢
  • 1970-01-01
  • 2020-09-06
  • 2018-01-10
  • 2022-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-12
  • 1970-01-01
相关资源
最近更新 更多