选择值的百分比满足阈值的行的子集

时间:2014-03-21 10:10:41

标签: r subset logical-operators

我有一个数据框,其中包含行中的值和列中的样本(两组,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的行。那1.5。这应该给我以下df:

df[c(4,8),]

我是Stackoverflow的新手,过去我曾被要求提供示例。我希望这很好!

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

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

使用以下选项选择所有样本均低于特定阈值的行的子集:

df[rowMeans(df)<1.5,]

选择&gt; = 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的行。那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澄清你正在通过列的字符串名称进行层次索引。看到他的解决方案,我没有必要复制它。)