如何利用rep()处理data.frame或向量,生成指定关联数据组合?
问题描述
我有一个data.frame列表dflist,结构如下:
dflist: [[12]] label site <chr> <int> [1] NODE_0000138 12 [2] NODE_0000222 12 [3] NODE_0000205 12 [4] NODE_0000241 12 [5] 061D03KR01 12 [6] 061D03KR03 12 [[15]] label site <chr> <int> [1] NODE_0000203 15 [2] 061D03OR17 15 [3] 061D03OR19 15 [4] 061D03UR28 15 [[18]] label site <chr> <int> [1] NODE_0000181 18 [2] NODE_0000226 18 [3] 061D03KR11 18 [4] 061D03OR02 18 [5] 061D03OR32 18
同时有一个记录关联关系的data.frame df:
df from to 1 12 18 2 12 35 3 15 18
需求是生成一个新的data.frame,根据df的每一行,生成from对应的dflist元素与to对应的dflist元素的所有可能组合。比如df第一行12对应18,要生成所有12组内label+site和18组内label+site的笛卡尔积组合,以此类推处理df所有行。试了for循环太繁琐,rep系列函数也没实现想要的重复次数,求更优方法。
解决方案
方法1:tidyverse工具链实现
加载dplyr和purrr,通过遍历关联关系行,生成笛卡尔积后合并结果:
library(dplyr) library(purrr) # 给dflist元素命名,确保能通过site值索引 names(dflist) <- names(dflist) %>% replace(is.na(.), as.integer(which(is.na(.)))) # 遍历df每一行生成组合并合并 result <- pmap_dfr(df, function(from, to) { df_from <- dflist[[as.character(from)]] df_to <- dflist[[as.character(to)]] # 跳过不存在的to对应的列表元素(比如示例中的35) if (is.null(df_to)) return(tibble()) # 生成笛卡尔积并重命名列避免冲突 df_from %>% rename(from_label = label, from_site = site) %>% crossing(df_to %>% rename(to_label = label, to_site = site)) })
方法2:data.table高效实现
适合处理大数据量,利用CJ函数快速生成笛卡尔积:
library(data.table) # 给dflist元素命名 names(dflist) <- as.character(names(dflist)) %>% replace(is.na(.), as.integer(which(is.na(.)))) dt <- as.data.table(df) # 按关联关系分组生成组合,合并结果 result <- rbindlist(dt[, { df_from <- dflist[[as.character(from)]] df_to <- dflist[[as.character(to)]] if (is.null(df_to)) return(NULL) CJ(df_from, df_to, sorted = FALSE) %>% setnames(c("from_label", "from_site", "to_label", "to_site")) }, by = .(from, to)]$V1)
方法3:基础R原生实现
无需加载第三方包,用expand.grid生成笛卡尔积:
# 给dflist元素命名 names(dflist) <- as.character(names(dflist)) %>% replace(is.na(.), as.integer(which(is.na(.)))) # 遍历生成每个关联关系的组合列表 result_list <- lapply(1:nrow(df), function(i) { from_val <- df$from[i] to_val <- df$to[i] df_from <- dflist[[as.character(from_val)]] df_to <- dflist[[as.character(to_val)]] if (is.null(df_to)) return(NULL) expand.grid(df_from, df_to, stringsAsFactors = FALSE) %>% setNames(c("from_label", "from_site", "to_label", "to_site")) }) # 合并所有非空结果 result <- do.call(rbind, Filter(Negate(is.null), result_list))
内容的提问来源于stack exchange,提问作者Andrea R
相关产品推荐
相关产品推荐

