r - 将函数应用于数据框中的分组行

标签 r dplyr purrr

这个问题在这里已经有了答案:





Split dataframe using two columns of data and apply common transformation on list of resulting dataframes

(2 个回答)


4年前关闭。




我创建了一个函数来计算一些生物统计数据,例如物种范围边缘。这是该函数的简化版本:

range_stats <- function(rangedf, lat, lon, weighting, na.rm=T){
  cent_lat <- weighted.mean(x=rangedf[,lat], w=rangedf[,weighting], na.rm=T)
  cent_lon <- weighted.mean(x=rangedf[,lon], w=rangedf[,weighting], na.rm=T)
out <- data.frame(cent_lat, cent_lon)    
return(out)
} 

我想将此应用于一个大型数据框,其中每一行都是对一个物种的观察。因此,我希望该函数按一组指定的列对行进行分组,然后为每个组计算这些统计信息。这是一个测试数据框:
LATITUDE <- c(27.91977, 21.29066, 26.06340, 28.38918, 25.97517, 27.96313)
LONGITUDE <- c(-175.8617, -157.8645, -173.9593, -178.3571, -173.9679, -175.7837)
BIOMASS <- c(4.3540488, 0.2406332, 0.2406332, 2.1419699, 0.3451426, 1.0946017)
SPECIES <- c('Abudefduf abdominalis','Abudefduf abdominalis','Abudefduf abdominalis','Chaetodon lunulatus','Chaetodon lunulatus','Chaetodon lunulatus')
YEAR <- c('2005', '2005', '2014', '2009', '2009', '2015')
testdf <- data.table(LATITUDE, LONGITUDE, BIOMASS, SPECIES, YEAR)

我想将此函数应用于物种和年份的每个独特组合以计算汇总统计数据,即以下内容:
testresult <- testdf %>%
  group_by(SPECIES, YEAR) %>%
  range_stats(lat="LATITUDE",lon="LONGITUDE",weighting="BIOMASS",na.rm=T)

但是,上面的代码不起作用(我得到一个 (list) object cannot be coerced to type 'double' 错误),我不确定如何解决这个问题。

最佳答案

由于您添加了 dplyr 的标签和 purrr ,我假设您对 tidyverse 感兴趣解决方案。所以下面我将演示一个基于 tidyverse 的解决方案。 .

首先,您的range_stats是有问题的。这就是您收到错误消息的原因。 weighted.mean期待 x 的向量和 w争论。但是,如果 rangedftibble , 子集 tibble 的方式,如 rangedf[,lat]仍将返回一列 tibble .更好的方法是使用 pull来自 dplyr包裹。

library(tidyverse)
range_stats <- function(rangedf, lat, lon, weighting, na.rm=T){
  cent_lat <- weighted.mean(x = rangedf %>% pull(lat), 
                            w = rangedf %>% pull(weighting), na.rm=T)
  cent_lon <- weighted.mean(x = rangedf %>% pull(lon), 
                            w = rangedf %>% pull(weighting), na.rm=T)
  out <- data.frame(cent_lat, cent_lon)    
  return(out)
} 

接下来,你创建数据框的方式就OK了,但是data.table来自data.table包,您将创建一个 data.table ,而不是 tibble .我以为你想使用 tidyverse 中的方法,所以我改了data.tabledata_frame如下。
LATITUDE <- c(27.91977, 21.29066, 26.06340, 28.38918, 25.97517, 27.96313)
LONGITUDE <- c(-175.8617, -157.8645, -173.9593, -178.3571, -173.9679, -175.7837)
BIOMASS <- c(4.3540488, 0.2406332, 0.2406332, 2.1419699, 0.3451426, 1.0946017)
SPECIES <- c('Abudefduf abdominalis','Abudefduf abdominalis','Abudefduf abdominalis','Chaetodon lunulatus','Chaetodon lunulatus','Chaetodon lunulatus')
YEAR <- c('2005', '2005', '2014', '2009', '2009', '2015')
testdf <- data_frame(LATITUDE, LONGITUDE, BIOMASS, SPECIES, YEAR)

现在,您说要申请 range_stats SPECIES 的每个组合的函数和 YEAR .一种方法是将数据帧拆分为数据帧列表,并使用 lapply家庭功能。但在这里我想向您展示如何使用 map家庭功能来完成这个任务为map来自purrr包,它是 tidyverse 的一部分.

我们可以先根据 SPECIES 创建一个组索引和 YEAR .
testdf2 <- testdf %>%
  mutate(Group = group_indices(., SPECIES, YEAR)) 
testdf2
# A tibble: 6 x 6
  LATITUDE LONGITUDE   BIOMASS               SPECIES  YEAR Group
     <dbl>     <dbl>     <dbl>                 <chr> <chr> <int>
1 27.91977 -175.8617 4.3540488 Abudefduf abdominalis  2005     1
2 21.29066 -157.8645 0.2406332 Abudefduf abdominalis  2005     1
3 26.06340 -173.9593 0.2406332 Abudefduf abdominalis  2014     2
4 28.38918 -178.3571 2.1419699   Chaetodon lunulatus  2009     3
5 25.97517 -173.9679 0.3451426   Chaetodon lunulatus  2009     3
6 27.96313 -175.7837 1.0946017   Chaetodon lunulatus  2015     4

如您所见,Group是一个显示索引号的新列。现在我们可以根据 Group 拆分数据帧,然后使用 map_dfr申请range_stats功能。
testresult <- testdf2 %>%
  split(.$Group) %>%
  map_dfr(range_stats, lat = "LATITUDE",lon = "LONGITUDE", 
          weighting = "BIOMASS", na.rm = TRUE, .id = "Group")
testresult
  Group cent_lat  cent_lon
1     1 27.57259 -174.9191
2     2 26.06340 -173.9593
3     3 28.05418 -177.7480
4     4 27.96313 -175.7837

请注意 map_dfr可以自动将数据框的输出列表绑定(bind)到单个数据框。 .id = "Group"表示我们要创建一个名为 Group 的列基于列表元素的名称。

我将过程分为两个步骤,但当然它们可以全部在一个管道中,如下所示。
testresult  <- testdf %>%
  mutate(Group = group_indices(., SPECIES, YEAR))  %>%
  split(.$Group) %>%
  map_dfr(range_stats, lat = "LATITUDE",lon = "LONGITUDE", 
          weighting = "BIOMASS", na.rm = TRUE, .id = "Group")

如果你愿意,testresult可以与 testdf 合并使用 left_join ,但我将在这里停止 testresult可能已经是您想要的输出。我希望这有帮助。

关于r - 将函数应用于数据框中的分组行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46415198/

相关文章:

r - 在 R 中使用条件进行内部连接

r - 为什么map %>% as.data.frame 给出的结果与map_df 不同?

r - 迭代数据帧,其中每次迭代都有效地依赖于 R 中的前一项

r - 如何在没有数据或仅使用预测系数的情况下保存 glm 结果?

R-如何在 R 中定义具有不定数量参数的函数

r - 使用 lubridate 和 dplyr 将多列转换为日期

r - dplyr 0.5 : arrange() using groupings

r - 如何使用跨函数和动态生成的函数列表进行变异

r - 计算R中两条密度曲线的交点

r - 为什么 Shiny 的应用程序使用突出显示功能和 selectize=TRUE 将虚假小部件添加到 Plotly 图表中?