【问题标题】:Selecting a subset of rows where a % of the values meet the threshold选择 % 的值满足阈值的行子集
【发布时间】:2014-03-21 10:10:41
【问题描述】:

我有一个数据框,其中行中的值和列中的样本(两组,A 和 B)。例子df:

df <- rbind(rep(1, times = 10), 
        c(rep(1, times = 9), 2), 
        c(rep(1, times = 8), rep(2, times = 2)),
        c(rep(1, times = 7), rep(2, times = 3)), rep(1, times = 10), 
        c(rep(1, times = 9), 2), 
        c(rep(1, times = 8), rep(2, times = 2)), 
        c(rep(2, times = 7), rep(1, times = 3)))
colnames(df) <- c("A1", "A2", "A3", "A4", "A5",
              "B1", "B2", "B3", "B4", "B5")
row.names(df) <- 1:8

我一直在使用以下方法选择所有样本都低于某个阈值的行子集:

selected <- apply(df, MARGIN = 1, function(x) all(x < 1.5))
df.sel <- df[selected,]

结果是

df[c(1,5),]

我需要另外两种选择。首先是选择,例如,至少 90% 的样本低于阈值 1.5 的所有行。这样的结果应该是:

df[c(1,2,5,6)]

第二种是按组选择。比如说,至少一个组中至少 50% 的值大于 1.5 的行。这应该给我以下df:

df[c(4,8),]

我是 Stackoverflow 的新手,过去曾有人要求我举例说明。我希望这很好!

【问题讨论】:

  • 如果您将语言添加为标签更容易找到可以帮助您的开发人员
  • 完成,很抱歉,谢谢!
  • a) 你能让你的数据框值更加多样化吗?几乎全是 b) 不要通过声明变量 select 来影响内置 select
  • apply(df, MARGIN = 1, ...) 可以避免,在这种情况下(几乎全部)你可以作弊,例如df[rowMeans(df)&lt;1.5, ]
  • @Jake:我的错。我在想subset(..., select=...)select 参数,有人发布了一个关于使用变量select 进行阴影的问题,它引起了混乱。

标签: r subset logical-operators


【解决方案1】:
df[!rowSums(df >= 1.5),]
##   A1 A2 A3 A4 A5 B1 B2 B3 B4 B5
## 1  1  1  1  1  1  1  1  1  1  1
## 5  1  1  1  1  1  1  1  1  1  1

df[rowMeans(df < 1.5) >= 0.9,]
##   A1 A2 A3 A4 A5 B1 B2 B3 B4 B5
## 1  1  1  1  1  1  1  1  1  1  1
## 2  1  1  1  1  1  1  1  1  1  2
## 5  1  1  1  1  1  1  1  1  1  1
## 6  1  1  1  1  1  1  1  1  1  2

idx <- apply(df, 1, function(x) {
    any(tapply(x, gsub("[0-9]", "", names(x)), function(y) mean(y > 1.5)) > 0.5)
    })

df[idx,]
##   A1 A2 A3 A4 A5 B1 B2 B3 B4 B5
## 4  1  1  1  1  1  1  1  2  2  2
## 8  2  2  2  2  2  2  2  1  1  1

【讨论】:

  • @杰克,非常感谢。您的解决方案适用于我的真实数据集(第三个让我很高兴!)。不过我有两个问题,我不明白你为什么使用 !rowSums 而不是 rowMeans。它确实有效,但我不明白为什么。第1行的总和不应该是10吗?如果我理解,那不应该出现在输出中。我的另一个问题是关于你的第三个例子。如果我想在 80% 的样本中选择均值(y>1.5),我将调整为 >0.2。它是否正确?再次感谢,很遗憾我无法投票!
  • @ChristianD rowSumsdf &gt;= 1.5 上被调用,这是一个data.frame 填充logicals。看看df &gt;= 1.5 的输出即可。所以rowSums(df &gt;= 1.5) 将是每行中大于或等于 1.5 的值的数量。 !rowSums(df &gt;= 1.5) 等价于 rowSums(df &gt;= 1.5) != 0。在第三个示例中,您将其更改为 &gt; 0.8。在这个示例数据上尝试一下,看看返回了哪些行!当我今天晚些时候有机会时,我会在答案中添加更多解释
【解决方案2】:

在您几乎全为一的特定情况下,您可以使用rowMeanscolMeans 完成所有这些操作。 (还有plyr::colwise 用于更复杂的东西)。

使用以下方法选择所有样本都低于某个阈值的行子集:

df[rowMeans(df)<1.5,]

选择 >=90% 的样本低于阈值 1.5 的所有行。 (如果我们知道唯一的另一个值是 2,我们会更容易利用)

您可以直接计算'1'条目的比例:

> apply(df, 1, function(x) sum(x==1)) /ncol(df)
  1   2   3   4   5   6   7   8 
1.0 0.9 0.8 0.7 1.0 0.9 0.8 0.3

这样就可以得到你想要的行索引:

> apply(df, 1, function(x) sum(x==1)) /ncol(df) >= 0.9
    1     2     3     4     5     6     7     8 
 TRUE  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE 

以及你想要的行切片:

> df[ apply(df, 1, function(x) sum(x==1)) /ncol(df) >= 0.9 , ]
  A1 A2 A3 A4 A5 B1 B2 B3 B4 B5
1  1  1  1  1  1  1  1  1  1  1
2  1  1  1  1  1  1  1  1  1  2
5  1  1  1  1  1  1  1  1  1  1
6  1  1  1  1  1  1  1  1  1  2

第二种是按组选择。比如说,至少一个组中至少 50% 的值大于 1.5 的行。

除非我误解了您所说的“至少其中一个组”是什么意思, 你的例子是错误的。第 4 行不符合条件,只有第 8 行。

同样,您可以使用rowSums 作弊,或者:

> apply(df, 1, function(x) sum(x>=1.5)) /ncol(df) >= 0.5
1     2     3     4     5     6     7     8 
FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE 

这只会让你得到第 8 行而不是第 4 行,所以我误解了你吗? (Jake Burhead 澄清说您正在通过列的字符串名称进行分层索引。请参阅他的解决方案,我复制它没有意义。)

【讨论】:

  • 我也花了一段时间才弄清楚这些组。这些组似乎来自列名中的字母。所以第 4 行被选中,因为它在 B 组中有 5 个中的 3 个大于 1.5
  • @Jake-Burhead 谢谢!就像列上的分层索引......?
  • 感谢你们两位的解决方案。如果这个例子可能是简化的,我很抱歉。我应该付出更多的努力来准备 df。是我的错,下次再做!
  • ChristianD,对于新用户来说,你很棒。这个很酷。除了为有用的答案投票是件好事……
  • 我希望我能,但它告诉我我没有足够的声誉。另外,我尝试在两个答案上都打上绿色勾号,但我只能选择一个!我正在尽力.. :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多