如何使用for循环多参数功能应用到基于分组变量的数据帧?

问题描述 投票:1回答:2

Preamble

我提前道歉,我觉得以书面形式准确的问题表达非常困难,并认为这是通过查看代码最清晰。另外,我是比较新的R和必须使用合适的语言来准确地描述这种情况的麻烦。我认为解决的办法应该是很容易被人带着几分更多的经验指出,任何建议将不胜感激!

Description

我有我努力让自己在一组,由组的基础为此我写了一个功能的专门计算。功能是用户定义执行该专门的计算,需要4个参数(其中2个具有长度> 1),并输出一个值(因此输出不等于输入的长度)。虽然这种功能不工作,我需要能够高效率地将其应用到每个组中的数据帧(对于下面的重复的例子,有4个组,但是,在现实中,将有数百或基团的1000)。

我试图用应用功能,通常建议对于那些听起来类似这样的情况,但我至今没有成功使用非for循环的方法。我认为这是因为在数据帧中的每一行不与不同组相关联,而有与单个基团(下面再现的示例相关联的多个行有与每个基团,其是相同的相关联的21行实际数据)。

无论如何,这似乎是一个for循环将是我的功能应用到每个组相关联的行的简单方法。然而,我无法生成所需的输出。正如我在序言中提到,我觉得这只是因为我眺望/不知道的东西很基本的,如需要做一个循环或索引我的for循环里面不同的循环。

Reproducible Example

Functionally similar data

interval=0.05 #used here to generate v1 and again in the function
v1 = seq(0.00000000001,1.00000000001, by=interval) 
nrows = length(v1) #determines length of other variables
g1 = c(rep(23.4, nrows), rep(19.7, nrows),rep(25.2, nrows),rep(16.4, 
nrows))           
v2 = runif(length(g1), 0,1)
dat = as.data.frame(cbind(g1,v1,v2))

哪里:

  • g1为分组变量
  • v1是第一个参数,反复进行对每个分组变种
  • v2是第二个参数,表示与各V1相关联的概率
  • DAT是数据帧

The Function

(这是我的第一个功能,我想有一个更好的方式来写,但它的工作)

MyFunction = function(v1, v2, interval, nrows) {
  sum.prod = sum(v1[2:nrows-1] * v2[2:nrows-1])
  last.val = v2[nrows]/2
  out = 2 * (sum.prod+last.val) * interval
  out
  }

Proof that the function works

我提供了第一组变量计算(G1 = 23.4),以防万一它是有帮助的,以确认该功能的工作原理以及它是如何工作的,因为有这个功能没有文档

range1 = 1:nrows
g1.sub1 = dat$g1[range1]
v1.sub1 = dat$v1[range1]
v2.sub1 = dat$v2[range1]

g.first = 2 * ((v1.sub1[2] * v2.sub1[2])+
(v1.sub1[3] * v2.sub1[3]) + (v1.sub1[4] * v2.sub1[4]) +
(v1.sub1[5] * v2.sub1[5]) + (v1.sub1[6] * v2.sub1[6]) +
(v1.sub1[7] * v2.sub1[7]) + (v1.sub1[8] * v2.sub1[8]) +
(v1.sub1[9] * v2.sub1[9]) + (v1.sub1[10] * v2.sub1[10]) +
(v1.sub1[11] * v2.sub1[11]) + (v1.sub1[12] * v2.sub1[12]) +
(v1.sub1[13] * v2.sub1[13]) + (v1.sub1[14] * v2.sub1[14]) +
(v1.sub1[15] * v2.sub1[15]) + (v1.sub1[16] * v2.sub1[16]) +
(v1.sub1[17] * v2.sub1[17]) + (v1.sub1[18] * v2.sub1[18]) +
(v1.sub1[19] * v2.sub1[19]) + (v1.sub1[20] * v2.sub1[20]) +
v2.sub1[21] / 2) * interval

g.first

其中由给定的值相匹配:

MyFunction(v1 = v1.sub1, v2 = v2.sub1, interval = interval, nrows=nrows)

Where I am Stuck: The For Loop

正如我在说明中提到,我已经试过各种方法来解决这个问题,包括申请家庭的功能没有运气。下面的代码表示我来最接近的一次。然而,这只是给我的第一个元素在G1(23.4)的正确值,而不是四次,每次的四大要素在G1(23.4,19.9.25.2,16.4)正确的值一次。

g=c(unique((g1)))
out=NULL
for(i in seq_along(g)){
out[i]=MyFunction( v1 = v1, v2 = v2, interval = interval, nrows = 
nrows)
}
out

Attempt to Troubleshoot the For Loop

我可以强制上述用于循环以产生类似于所期望的结果的东西,但该范围必须为每个组指定,并且由于实际数据具有基团,而不是仅仅4基团和基团的总数的100秒是事先不知道这不是一个可行的解决方案。

g=c(unique((g1)))

range1 = 1:nrows
range2 = (nrows+1):(nrows*2)
range3 = (nrows*2+1):(nrows*3)
range4 = (nrows*3+1):(nrows*4)

out1=NULL
out2=NULL
out3=NULL
out4=NULL

for(i in seq_along(g)){
out1[i]=MyFunction( v1 = dat$v1[range1], v2 = dat$v2[range1], 
interval = interval, nrows = nrows)
out2[i]=MyFunction( v1 = dat$v1[range2], v2 = dat$v2[range2], 
interval = interval, nrows = nrows)
out3[i]=MyFunction( v1 = dat$v1[range3], v2 = dat$v2[range3], 
interval = interval, nrows = nrows)
out4[i]=MyFunction( v1 = dat$v1[range4], v2 = dat$v2[range4], 
interval = interval, nrows = nrows)
}

out1
out2
out3
out4

The Desired Output

理想情况下,最终输出将是一个表/矩阵/列表/数据包含g1的每个值,并通过函数“去”相应的输出值的帧

就像是:

g1      out
23.4    some value between 0 and 1
19.9    some value between 0 and 1
25.2    some value between 0 and 1
16.4    some value between 0 and 1

Concluding Thoughts

由于我的“尝试排除For循环”最终能够以不希望的方式提供正确的输出,尽管(劳动强度大,不可扩展,并输出4个相同值的每个组的每个组,而不是1倍的值),我认为这表明我的代码是缺乏一些基本的东西(例如,另一个循环,不同的变量seq_along,索引不当等)。我希望这是容易让有经验的用户识别和解释,因为我难住了。

提前致谢!

r for-loop indexing subset scalability
2个回答
0
投票

我知道你问一个for循环,但是因为你可能已经见过的,通常有一种更好的方式来做到这一点。我猜你不熟悉data.table包呢,把它当做一个增压data.frame

所以,你想要做的是应用MyFunction您的数据,由列g1分组。这可以在data.table通过以下方式轻松实现。

library(data.table)
DT <- as.data.table(dat)
DT[, .(out = MyFunction(v1, v2, interval, .N)), by = g1]

那么这些行做的是库(您可能必须与install.packages('data.table')先安装它,然后你data.frame转换为data.table。最后,计算列outMyFunction应用于v1, v2, interval and .N.N分组(认为g1为NROWS的)第一负荷。

我认为,这达到自己的目标,如果你有任何问题随时问。希望这可以帮助。


0
投票

下面是一个使用tidyverse的方法。

首先,让我们看一下例子,有几行,捕捉你所描述的精简处理中更换的MyFunction:

library(tidyverse)
dat %>%
  slice(1:21) %>%  # Just the first grouping variable
  slice(2:n()) %>% # Exclude first row; has small impact since v1[1] is nearly zero already...
  mutate(prod = if_else(row_number() < n(),  # For all rows but the last one in the group,
                        v1 * v2,             # ... get the product of v1 and v2
                        v2/2)) %>%           # ... or have of v2, for the last row
  summarize(out = 2 * sum(prod) * interval)  # Sum the "prod" row, * 2 * interval

#        out
#1 0.5980449

要为G1的所有组做到这一点,我们要补充group_by第一,然后做同样的总结步骤分别对每个组:

dat %>%
  group_by(g1) %>%
  slice(1:21) %>%  # Just the first grouping variable
  slice(2:n()) %>% # Exclude first row; has small impact since v1[1] is nearly zero already...
  mutate(prod = if_else(row_number() < n(),  # For all rows but the last one in the group,
                        v1 * v2,             # ... get the product of v1 and v2
                        v2/2)) %>%           # ... or have of v2, for the last row
  summarize(out = 2 * sum(prod) * interval)  # Sum the "prod" row, * 2 * interval

## A tibble: 4 x 2
#     g1   out
#  <dbl> <dbl>
#1  16.4 0.342
#2  19.7 0.514
#3  23.4 0.598
#4  25.2 0.568
© www.soinside.com 2019 - 2024. All rights reserved.