R:使用apply family而不是for循环用于数据帧

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

首先,一些样本数据:

location <- c("A","B","C","D","E")
mat <- as.data.frame(matrix(runif(1825),nrow=5,ncol=365))
t1<- c(258,265,306,355)
t2<- c(258,270,302,352)
t3<- c(258,275,310,353)
t4<- c(258,280,303,355)
t5<- c(258,285,312,356)
ts<-rbind(t1,t2,t3,t4,t5)
dat <-as.data.frame(cbind(location,mat,ts))
names(dat)[367:370] <- c("pl","vg","re","me")

qazxsw poi是网站的名称。 qazxsw poi到qazxsw poi是每日降雨量(location是一年中的第一天)。我想做的是:

对于每一行(V1),我想根据最后四列V365V1locationpl(指定一年中的几天)产生三个降雨量值

例如,对于位置vg,最后四列是:

re me = 258 = 265 = 306 A pl = 355

因此,对于位置vg,我想产生三个降雨量值,这些降雨量值来自:

reme

AV258

V264V265

并为所有五个地点做到这一点。

我做的是:

V305

我想避免使用V306循环并使用V355函数。但是,我不熟悉如何使用apply函数一次性计算所有行(位置)。任何人都可以告诉我如何去做吗?

谢谢

编辑

如果我有其中一个降雨量值为NA且其他日期为NA的地点,我该如何修改下面接受的答案代码。这是样本数据

 for(j in unique(dat$location)){

    loc <- dat[dat$location == j,]

    pl.val <- loc$pl + 1 # have to add + 1 since the rainfall starts from the second column
   vg.val <- loc$vg + 1
   re.val <- loc$re + 1
   me.val <- loc$me + 1

   rain1 <- sum(loc[,pl.val:vg.val]) 
   rain2 <- sum(loc[,(vg.val+ 1):re.val]) 
   rain3 <- sum(loc[,(re.val + 1):me.val]) 
}     
r for-loop apply
2个回答
1
投票

我假设你想要速度。

我认为你的数据形式不好计算,因为只有col1是字符,col367:370的种类不同,而且很宽。也许按行计算并不是一个好主意。基本上R是很好的计算col col。

如果我是你,我会准备如下表格的数据;

for

我建议apply计算每对cols。 location <- c("A","B","C") mat <- as.data.frame(matrix(runif(365*3),nrow=3,ncol=365)) t1<- c(258,265,306,355) t2<- c(258,NA,NA,NA) t3<- c(258,275,310,353) ts<-rbind(t1,t2,t3) dat <-as.data.frame(cbind(location,mat,ts)) names(dat)[367:370] <- c("pl","vg","re","me") dat[2,-c( 367:370)] <- NA library(tidyverse) dat1 <- dat[, -c(1, 367:370)] %>% t() %>% as.tibble() %>% set_names(location) dat2 <- dat[, 367:370] %>% t() %>% as.tibble() %>% set_names(location) 的每个col,map2().x的每个col(它们被视为向量)。下面的代码是你的50倍。

dat1

[additionnl(apply,mapply)]

注意:由于转换为矩阵,.y难以处理具有字符和数字的dat2。因此,如果您使用map2(dat1, dat2, ~ { pl.val <- .y[1] vg.val <- .y[2] re.val <- .y[3] me.val <- .y[4] rain1 <- sum(.x[pl.val:vg.val]) rain2 <- sum(.x[(vg.val+ 1):re.val]) rain3 <- sum(.x[(re.val + 1):me.val]) c(rain1 = rain1, rain2 = rain2, rain3 = rain3) } ) ,则需要删除位置col。

apply()

data.frameapply()大致相同。在这个问题中,apply(dat[,-1], MARGIN = 1, function(x){ pl.val <- x[367 - 1] vg.val <- x[368 - 1] re.val <- x[369 - 1] me.val <- x[370 - 1] rain1 <- sum(x[pl.val:vg.val]) rain2 <- sum(x[(vg.val+ 1):re.val]) rain3 <- sum(x[(re.val + 1):me.val]) c(rain1 = rain1, rain2 = rain2, rain3 = rain3) }) 表现最佳。

mapply()

[基准]

map2()

[附加2(错误处理)]

当没有NA时,下面的代码几乎与上面的代码一样快。 (注意:如果它在一行中,你可以省略mapply()mapply(function(.x, .y){ pl.val <- .y[1] vg.val <- .y[2] re.val <- .y[3] me.val <- .y[4] rain1 <- sum(.x[pl.val:vg.val]) rain2 <- sum(.x[(vg.val+ 1):re.val]) rain3 <- sum(.x[(re.val + 1):me.val]) c(rain1 = rain1, rain2 = rain2, rain3 = rain3) }, dat1, dat2) ,例如Unit: microseconds expr min lq mean median uq max neval cld forloop_method() 14154.075 15074.555 17110.4060 16588.1200 18416.387 25869.836 100 c map2_method() 205.586 234.263 325.8762 313.9395 333.633 2072.911 100 a apply_method() 1617.443 1684.812 1913.9187 1783.2480 1933.216 4189.687 100 b mapply_method() 154.972 185.079 213.9370 210.2300 225.978 468.690 100 a 。)

{}

1
投票

我不确定你想要什么样的返回雨天?它们是否会被绑定为3个新列?

基本上,这是代码......我将逐步介绍:对于if(...) { A } else { B } data.frame中的每一行,选择代表日期的列,然后构建这些数字对应值的序列,但逐步降低下一个值这样我们每次都能获得正确的列。由于我们现在在数据的每个位置if(...) A else B上运行,将值转换为数字,并在results <- map2(dat1, dat2, ~ { pl.val <- .y[1] vg.val <- .y[2] re.val <- .y[3] me.val <- .y[4] rain1 <- if(is.na(pl.val) | is.na(vg.val)) NA else sum(.x[pl.val:vg.val], na.rm = T) rain2 <- if(is.na(vg.val) | is.na(re.val)) NA else sum(.x[(vg.val+ 1):re.val], na.rm = T) rain3 <- if(is.na(re.val) | is.na(me.val)) NA else sum(.x[(re.val + 1):me.val], na.rm = T) c(rain1 = rain1, rain2 = rain2, rain3 = rain3) } ) # If you want data.frame instead of list invoke("rbind", results) 步骤中对相应的列求和。使用datslice附加到我们从序列创建中获得的每个列号,并作为列表返回。然后我简单地用相应位置的ID命名列表向量...如果你想将它附加到data.frame,它也会很简单。

apply
© www.soinside.com 2019 - 2024. All rights reserved.