我希望那里的某个人可以帮助我找到我在R中使用我的代码时遇到的令人沮丧的问题的根源。我有一个由数据框组成的列表,我想要左边将每个元素连接到两个OTHER数据帧之一(称为A和B)。要加入哪些辅助数据帧取决于元素在列表中的位置。为了我的目的,我希望每个奇数元素都被左连接到A,并且每个偶数元素都被左连接到B.
library(dplyr)
DF <- data.frame(Num = c("1","2"), Let = c("a","b"), stringsAsFactors = FALSE)
A <- data.frame(Let = c("a","b"), Col = c("Yellow","Red"), stringsAsFactors = FALSE)
B <- data.frame(Let = c("a","b"), Col = c("Green","Blue"), stringsAsFactors = FALSE)
LIST <- list(DF, DF)
到目前为止,我已尝试以两种不同的方式做到这一点。第一种方法涉及if-else语句。如果我应用这样的语句来根据位置分配一个整数值,我会得到预期的结果。同样,当我离开时 使用if-else语句,只需在列表中执行一系列左连接 元素,一切都按预期工作。
lapply(seq_along(LIST), function(x, {ifelse((x %% 2)==0, y[[x]] <- 1, y[[x]] <- 2)}, y = LIST)
lapply(seq_along(LIST), function(x, {left_join(y[[x]], A, by = c("Let"))}, y = LIST)
当我遇到问题时,我尝试将if-else语句和左连接组合在一起。特别是,我最终得到一个由列表组成的列表 其中仅保留原始相应数据帧的第一列。
lapply(seq_along(LIST), function(x, y) {ifelse((x %% 2)==0, left_join(y[[x]], A, by = c("Let")), left_join(y[[x]], B, by = c("Let")))}, y = LIST)
这是我想要获得的输出:
[[1]]
Let Num Col
1 a 1 Yellow
2 b 2 Red
[[2]]
Let Num Col
1 a 1 Green
2 b 2 Blue
我确定这个问题是一个荒谬简单的解决方案。有谁能看到它?
提前致谢! 马修
P.S。:我还尝试了第二种方法,应用子集而不是if-else语句。然而,我再次陷入困境。下面的第一行按预期工作,但第二行返回错误,好像R不识别列表索引:
lapply(seq_along(LIST), function(x, y) {left_join(y[[x > 0]], A, by = c("Let"))}, y = LIST)
lapply(seq_along(LIST), function(x, y) {left_join(y[[x == 1]], A, by = c("Let"))}, y = LIST)
Error in y[[x == 1]] : attempt to select less than one element in integerOneIndex
答案 0 :(得分:3)
我不完全确定我理解你的问题。
以下解决方案基于您的附言中lapply(seq_along(LIST), function(x, y) {left_join(y[[x > 0]], A, by = c("Let"))}, y = LIST)
的输出的再现。请注意,其他lapply
行会抛出错误。
library(tidyverse);
map(list(A, B), function(x) left_join(DF, x))
#Joining, by = "Let"
#Joining, by = "Let"
#[[1]]
# Num Let Col
#1 1 a Yellow
#2 2 b Red
#
#[[2]]
# Num Let Col
#1 1 a Green
#2 2 b Blue
我们使用purrr:map
与dplyr::left_join
加入A
和B
加入DF
。
使用Map
和merge
:
mapply(function(x) merge(DF, x, by = "Let"), list(A, B), SIMPLIFY = F)
#[[1]]
# Let Num Col
#1 a 1 Yellow
#2 b 2 Red
#
#[[2]]
# Let Num Col
#1 a 1 Green
#2 b 2 Blue
答案 1 :(得分:2)
使用base::mapply()
返回有条件合并的数据框列表。在这里,我提供了两个输入:
seq.along( along.with = LIST )
获取System.setProperty("webdriver.chrome.driver","/usr/bin/chromedriver");
WebDriver driver = new ChromeDriver();
driver.get("https://mvnrepository.com");
driver.close();
中的元素数量;和LIST
本身。 LIST
参数是一个匿名函数,它接收两个输入 - FUN
和i
- 并测试j
中的当前元素是偶数还是奇数编号使用left-join执行base::merge()。
如果LIST
中i th 元素的result of the modulus operator等于零,则左连接seq.along( along.with = LIST )
到j th < B
中的/ sup>元素;如果它不等于零,则在LIST
中的j th 元素上执行left-join A
。
LIST
# load data
DF <- data.frame(Num = c("1","2"), Let = c("a","b"), stringsAsFactors = FALSE)
A <- data.frame(Let = c("a","b"), Col = c("Yellow","Red"), stringsAsFactors = FALSE)
B <- data.frame(Let = c("a","b"), Col = c("Green","Blue"), stringsAsFactors = FALSE)
LIST <- list(DF, DF)
# goal: left join all odd elements in LIST[[j]]
# to `A` and all even elements to `B`
merged.list <-
mapply( FUN = function( i, j )
if( i %% 2 == 0 ){
merge( x = j
, y = B
, by = "Let"
, all.x = TRUE )
} else{
merge( x = j
, y = A
, by = "Let"
, all.x = TRUE )
}
, seq_along( along.with = LIST )
, LIST
, SIMPLIFY = FALSE )
# view results
merged.list
# [[1]]
# Let Num Col
# 1 a 1 Yellow
# 2 b 2 Red
#
# [[2]]
# Let Num Col
# 1 a 1 Green
# 2 b 2 Blue
# end of script #
答案 2 :(得分:1)
MauritsEvers已经回答了你的问题,但我认为我会解决R语法和编程逻辑中的明显错误。专注于第一次lapply-call:
lapply(seq_along(LIST), function(x, {ifelse((x %% 2)==0, y[[x]] <- 1, y[[x]] <- 2)}, y = LIST)
首先,也许是微不足道的是第一个)
- 动作中缺少的结束lapply
参数列表。接下来更基本的是错误地使用ifelse
作为编程结构。 ifelse
函数不是为数据对象的串行测试而设计的。它仅设计为沿单个矢量应用。如果要进行连续选择,if(.){.}else{.}
- 函数可能应该在lapply
调用中使用。
然而,(现在尝试实现第一段而不是继续纠正代码)我认为在LIST
上使用逻辑索引(使用R&#39;隐式回收过程)会更简单 - 对象而不是任何循环过程。 (这是不一个整数解决方案。)此代码将LIST分段为&#34; odd&#34;和&#34;甚至&#34;组件:
oddList <- LIST[ c(TRUE,FALSE) ] # implicit seq-along by virtue of recycling
evenList <- LIST[ c(FALSE,TRUE) ]
我们可以使用这种类型的结果来制作两个完成既定目标的单线程。我把LIST-object设为四宽而不是两宽。
Abig <- Reduce( function(x,y) {merge(x,y,by="Let")}, LIST, init=A)
Warning message:
In merge.data.frame(x, y, by = "Let") :
column names ‘Num.x’, ‘Num.y’ are duplicated in the result
Bbig <- Reduce( function(x,y) {merge(x,y,by="Let")}, LIST, init=B)
Warning message:
In merge.data.frame(x, y, by = "Let") :
column names ‘Num.x’, ‘Num.y’ are duplicated in the result
这只是一个警告,在这里你可以看到警告的内容:
> Abig
Let Col Num.x Num.y Num.x Num.y
1 a Yellow 1 1 1 1
2 b Red 2 2 2 2
如果你需要那些标记为唯一的重复列名(并且我很瘦,那将是一个好主意),那么:
names(Abig)[ grep("Num", names(Abig)) ] <-
paste0("Num.", seq_along( grep("Num", names(Abig)) ) )
Abig
Let Col Num.1 Num.2 Num.3 Num.4
1 a Yellow 1 1 1 1
2 b Red 2 2 2 2
答案 3 :(得分:1)
此解决方案非常类似于(@MauritsEvers&amp; @aspiringurbandatascientist)已在此处发布的mapply
解决方案,但它使用了join
data.frames的不同方法。 dplyr::left_join
已用于满足目的。
library(dplyr)
# Using mapply and left_join
mapply(function(x,y){
if(y %% 2 == 1){
left_join(x, A, by="Let")
}else {
left_join(x, B, by="Let")
}
}, LIST, seq_along(LIST), SIMPLIFY = FALSE)
# [[1]]
# Num Let Col
# 1 1 a Yellow
# 2 2 b Red
#
# [[2]]
# Num Let Col
# 1 1 a Green
# 2 2 b Blue
答案 4 :(得分:0)
为了清晰起见,我重复了一些示例数据
数据强>
DF1 <- data.frame(Num1 = c("1","2"), Let = c("a","b"), stringsAsFactors = FALSE)
DF2 <- data.frame(Num2 = c("3","4"), Let = c("a","b"), stringsAsFactors = FALSE)
DF3 <- data.frame(Num3 = c("5","6"), Let = c("a","b"), stringsAsFactors = FALSE)
DF4 <- data.frame(Num4 = c("7","8"), Let = c("a","b"), stringsAsFactors = FALSE)
A <- data.frame(Let = c("a","b"), Col = c("Yellow","Red"), stringsAsFactors = FALSE)
B <- data.frame(Let = c("a","b"), Col = c("Green","Blue"), stringsAsFactors = FALSE)
LIST <- list(DF1, DF2, DF3, DF4)
<强>解决方案强>
library(dplyr)
library(purrr)
LIST_odd <- LIST[as.logical(seq_along(LIST)%%2)]
LIST_even <- LIST[!as.logical(seq_along(LIST)%%2)]
merge_odd <- reduce(LIST_odd,left_join,.init=A)
# Let Col Num1 Num3
# 1 a Yellow 1 5
# 2 b Red 2 6
merge_even <- reduce(LIST_even,left_join,.init=B)
# Let Col Num2 Num4
# 1 a Green 3 7
# 2 b Blue 4 8
如果您不想使用purrr
,那么仅使用dplyr
和base
提供相同的结果:
Reduce(left_join,LIST_odd,A)
Reduce(left_join,LIST_even,B)
或100%基数:
Reduce(function(x,y) merge(x,y,all.x=TRUE),LIST_odd,A)
Reduce(function(x,y) merge(x,y,all.x=TRUE),LIST_even,B)