[R]:根据条件行位置将函数应用于列

Posted

技术标签:

【中文标题】[R]:根据条件行位置将函数应用于列【英文标题】:[R]: applying a function to columns based on conditional row position 【发布时间】:2015-03-15 09:36:19 【问题描述】:

我试图在数据框中按列查找在遇到该列的最大值后满足特定条件的观察数。

这是一个高度简化的例子:

fake.dat<-data.frame(samp1=c(5,6,7,5,4,5,10,5,6,7), samp2=c(2,3,4,6,7,9,2,3,7,8), samp3=c(2,3,4,11,7,9,2,3,7,8),samp4=c(5,6,7,5,4,12,10,5,6,7))

       samp1 samp2 samp3 samp4
1      5     2     2     5
2      6     3     3     6
3      7     4     4     7
4      5     6    11     5
5      4     7     7     4
6      5     9     9    12
7     10     2     2    10
8      5     3     3     5
9      6     7     7     6
10     7     8     8     7

因此,假设我在排除一列中的所有观察值(直到并包括该列出现最大值的行)之后,试图找出每列大于 5 的观察值。

预期结果:

samp1 samp2 samp3 samp4 
   2     2     4    3 

我可以通过使用嵌套的for loops 排除我不想要的观察得到我想要的答案。

newfake.dat<-data.frame()

for(j in 1:length(fake.dat))
for(i in 1:nrow(fake.dat))
    ifelse(i>max.row[j],newfake.dat[i,j]<-fake.dat[i,j],"NA")
print(newfake.dat)

这会创建一个新的数据框,我可以在该数据框上运行一个简单的 apply 函数。

colcount<-apply(newfake.dat,2,function(x) (sum(x>5,na.rm=TRUE)))

   V1 V2 V3 V4
1  NA NA NA NA
2  NA NA NA NA
3  NA NA NA NA
4  NA NA NA NA
5  NA NA  7 NA
6  NA NA  9 NA
7  NA  2  2 10
8   5  3  3  5
9   6  7  7  6
10  7  8  8  7

V1 V2 V3 V4 
 2  2  4  3 

对于这个小型示例数据集来说,这一切都很好,但是对于任何接近我的真实数据集大小的东西来说,速度都非常慢。它们很大(2000 x 2000 或更大)且数量众多。我用我的一个文件的截断版本(更少的列,但相同的行数)尝试了它,它运行了至少 5 个小时(当我下班时我让它继续运行)。另外,除了能够运行应用函数之外,我真的不需要新的数据框。

有什么方法可以更有效地做到这一点?我尝试通过使用seq 和最大行数来限制apply 函数工作的行。

maxrow<-apply(fake.dat,2,function(x) which.max(x))
print(maxrow)

seq.att<-apply(fake.dat,2,function(x) 
    sum(x[which(seq(1,nrow(fake.dat))==(maxrow)):nrow(fake.dat)]>5,na.rm=TRUE))

这会引发此警告消息的四个实例:

1: In seq(1, nrow(fake.dat)) == (maxrow) :
  longer object length is not a multiple of shorter object length

如果我忽略警告消息并获得输出,它不会给我预期的答案:

samp1 samp2 samp3 samp4 
    2     3     3     3 

我还尝试使用while 函数,该函数一直在循环,所以我停止了它(我放错了为此尝试的代码)。

到目前为止,最有希望的结果来自嵌套的for loops,但我知道它的效率非常低,我希望有更好的方法。我还是 R 的新手,我确信我在某处遇到了一些语法。提前感谢您提供的任何帮助!

【问题讨论】:

【参考方案1】:

baseR 中的单行代码:

vapply(fake.dat,function(x) sum(x[(which.max(x)+1):length(x)]>5),1L)
#samp1 samp2 samp3 samp4 
#    2     2     4     3

【讨论】:

@akrun Tx。我概述了 OP 的单行,他走在正确的轨道上,但事情有点复杂。我的解决方案只不过是更有效地“改写”了他的解决方案。 谢谢。看看我哪里出错会很有帮助,很高兴知道我最初的努力至少在某个时候走上了正确的道路。【参考方案2】:

这是dplyr 中复制您在base R 中展示的相同过程的一种方法

library(dplyr)
fake.dat %>% 
        summarise_each(funs(sum(.[(which.max(.)+1):n()]>5,
                na.rm=TRUE)))
#   samp1 samp2 samp3 samp4
#1     2     2     4     3

如果需要分两步:

datNA <- fake.dat %>% 
               mutate_each(funs(replace(., seq_len(which.max(.)), NA)))

datNA %>% 
      summarise_each(funs(sum(.>5, na.rm=TRUE)))

【讨论】:

非常感谢 - 这对我的示例数据集非常有用。我还不太熟悉dplyr - 有没有办法在which.max 位中添加一个常量?在我的真实数据集中,我想查看一个低于最大值的设定值。 @NMc 你能在你的帖子中更新它吗?我不完全了解添加常量。 @NMc 也许,n &lt;- 3; fake.dat %&gt;% summarise_each(funs(sum(.[(which.max(.)+n):n()]&gt;5,na.rm=TRUE))) 是的,我没有包括关于添加常量的内容,因为我认为这是一个奇怪的、情境化的东西,我可以将其添加到我自己的代码中。我只是对dplyr 表示法感到困惑。感谢您的澄清!【参考方案3】:

这是使用data.table的一种方法:

library(data.table)
##
data <- data.frame(
  samp1=c(5,6,7,5,4,5,10,5,6,7), 
  samp2=c(2,3,4,6,7,9,2,3,7,8), 
  samp3=c(2,3,4,11,7,9,2,3,7,8),
  samp4=c(5,6,7,5,4,12,10,5,6,7))
##
Dt <- data.table(data)
##
R> Dt[,lapply(.SD,function(x)
    y <- x[(which.max(x)+1):.N]
    length(y[y>5])
  )
   samp1 samp2 samp3 samp4
1:     2     2     4     3

【讨论】:

以上是关于[R]:根据条件行位置将函数应用于列的主要内容,如果未能解决你的问题,请参考以下文章

python pandas-将带有两个参数的函数应用于列

如何根据不同 R 生态系统中的另一个向量重写代码,将函数应用于行子集?

在 Pandas 中使用 group by 时如何将“first”和“last”函数应用于列?

将条件应用于列列表的数据框过滤

基于应用于列的标量函数的索引

在 pandas 中将 lambda 函数应用于列失败