在 R 中,根据元素名称重组列表(rbind 和指示变量)
In R, reorganize list based on element names (rbind and indicator variable)
我正在尝试重新组织我的数据,基本上是 data.frames 的列表。
它的元素代表感兴趣的主题(A 和 B),对 x 和 y 的观察,在两个场合(1 和 2)收集。
我试图使这个列表包含 data.frames 引用主题,收集 x 和 y 的信息作为新变量存储在相应的 data.frames 中,而不是元素姓名:
library('rlist')
A1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
A2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
list <- list(A1=A1,A2=A2,B1=B1,B2=B2)
A <- do.call(rbind,list.match(list,"A"))
B <- do.call(rbind,list.match(list,"B"))
list <- list(A=A,B=B)
list <- lapply(list,function(x) {
y <- data.frame(x)
y$class <- c(rep.int(1,2),rep.int(2,2))
return(y)
})
> list
$A
x y class
A1.1 66 96 1
A1.2 76 58 1
A2.1 50 93 2
A2.2 57 12 2
$B
x y class
B1.1 58 56 1
B1.2 69 15 1
B2.1 77 77 2
B2.2 9 9 2
在我的真实世界问题中,有大约 500 个主题,并不总是两次,不同数量的观察。
所以我上面的例子只是为了说明我想去哪里,我被困在如何传递给 do.call-rbind 它应该根据元素名称绑定特定主题的元素作为新的列表元素在一起,同时分配一个新的变量。
对我来说,这是一个有点模糊的任务,我得到的最接近的是 rlist
包。 This 问题是相关的,但使用 unique
来识别元素,而在我的情况下,它似乎更像是一个正则表达式问题。
即使是有关如何使用 google 的说明、任何用于进一步研究的关键字等,我也会很高兴。
根据您提供的数据:
subj <- sub("[A-Z]*", "", names(lst))
newlst <- Map(function(x, y) {x[,"class"] <- y;x}, lst, subj)
首先,我们执行正则表达式调用以隔离将进入 class
列的数字。在这种情况下,我匹配大写字母并删除它们留下数字。因此,"A1"
变为 "1"
。请注意,真实姓名意味着不同的正则表达式模式。
然后我们使用 Map
为每个数据框创建一个新列并保存到一个名为 newlst
的新列表中。 Map 获取每个参数的第一个元素并执行函数,然后继续处理每个对象元素。所以首先使用lst
中的第一个数据框和subj
中的第一个数字。我使用的匿名函数是function(x,y) {x[, "class"] <- y; x}
。它需要两个参数。第一个是数据框,第二个是列值。
现在前进更容易了。我们可以创建一个名为 uniq.nmes
的向量来获取我们将组合的数据帧的名称。其中 "A1"
将变为 "A"
。然后我们可以对该匹配进行 rbind:
uniq.nmes <- unique(sub("\d", "", names(lst)))
lapply(uniq.nmes, function(x) {
do.call(rbind, newlst[grep(x, names(newlst))])
})
# [[1]]
# x y class
# A1.1 1 79 1
# A1.2 30 13 1
# A2.1 90 39 2
# A2.2 43 22 2
#
# [[2]]
# x y class
# B1.1 54 59 1
# B1.2 83 90 1
# B2.1 85 36 2
# B2.2 91 28 2
数据
A1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
A2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
lst <- list(A1=A1,A2=A2,B1=B1,B2=B2)
听起来你在做很多体操,因为你有一个特定的形式。我建议首先尝试使数据 tidy。无需阅读 link,快速总结就是将您的数据放入单个数据框中,以便轻松处理。
答案的快速版本(这里我使用 lst
而不是 list
作为名称以避免与内置的 list
混淆)是这样做的:
do.call(rbind,
lapply(seq(lst), function(i) {
lst[[i]]$type <- names(lst)[i]; lst[[i]]
})
)
这将创建一个数据框,其中有一列 "type",其中包含出现该行的列表项的名称。
使用稍微简化的初始数据:
lst <- list(A1=data.frame(x=rnorm(5)), A2=data.frame(x=rnorm(3)), B=data.frame(x=rnorm(5)))
lst
$A1
x
1 1.3386071
2 1.9875317
3 0.4942179
4 -0.1803087
5 0.3094100
$A2
x
1 -0.3388195
2 1.1993115
3 1.9524970
$B
x
1 -0.1317882
2 -0.3383545
3 0.8864144
4 0.9241305
5 -0.8481927
然后应用魔法函数
df <- do.call(rbind,
lapply(seq(lst), function(i) {
lst[[i]]$type <- names(lst)[i]; lst[[i]]
})
)
df
x type
1 1.3386071 A1
2 1.9875317 A1
3 0.4942179 A1
4 -0.1803087 A1
5 0.3094100 A1
6 -0.3388195 A2
7 1.1993115 A2
8 1.9524970 A2
9 -0.1317882 B
10 -0.3383545 B
11 0.8864144 B
12 0.9241305 B
13 -0.8481927 B
从这里我们可以尽情地加工;使用 df$subject <- gsub("[0-9]*", "", df$type)
之类的操作来提取 type
的非数字部分,并且 split
之类的工具可用于生成您在问题中提到的子列表。
此外,一旦成为这种形式,您可以使用 by
和 aggregate
等函数或 dplyr
或 data.table
等库来进行更高级的拆分-应用合并操作进行数据分析。
我正在尝试重新组织我的数据,基本上是 data.frames 的列表。 它的元素代表感兴趣的主题(A 和 B),对 x 和 y 的观察,在两个场合(1 和 2)收集。 我试图使这个列表包含 data.frames 引用主题,收集 x 和 y 的信息作为新变量存储在相应的 data.frames 中,而不是元素姓名:
library('rlist')
A1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
A2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
list <- list(A1=A1,A2=A2,B1=B1,B2=B2)
A <- do.call(rbind,list.match(list,"A"))
B <- do.call(rbind,list.match(list,"B"))
list <- list(A=A,B=B)
list <- lapply(list,function(x) {
y <- data.frame(x)
y$class <- c(rep.int(1,2),rep.int(2,2))
return(y)
})
> list
$A
x y class
A1.1 66 96 1
A1.2 76 58 1
A2.1 50 93 2
A2.2 57 12 2
$B
x y class
B1.1 58 56 1
B1.2 69 15 1
B2.1 77 77 2
B2.2 9 9 2
在我的真实世界问题中,有大约 500 个主题,并不总是两次,不同数量的观察。
所以我上面的例子只是为了说明我想去哪里,我被困在如何传递给 do.call-rbind 它应该根据元素名称绑定特定主题的元素作为新的列表元素在一起,同时分配一个新的变量。
对我来说,这是一个有点模糊的任务,我得到的最接近的是 rlist
包。 This 问题是相关的,但使用 unique
来识别元素,而在我的情况下,它似乎更像是一个正则表达式问题。
即使是有关如何使用 google 的说明、任何用于进一步研究的关键字等,我也会很高兴。
根据您提供的数据:
subj <- sub("[A-Z]*", "", names(lst))
newlst <- Map(function(x, y) {x[,"class"] <- y;x}, lst, subj)
首先,我们执行正则表达式调用以隔离将进入 class
列的数字。在这种情况下,我匹配大写字母并删除它们留下数字。因此,"A1"
变为 "1"
。请注意,真实姓名意味着不同的正则表达式模式。
然后我们使用 Map
为每个数据框创建一个新列并保存到一个名为 newlst
的新列表中。 Map 获取每个参数的第一个元素并执行函数,然后继续处理每个对象元素。所以首先使用lst
中的第一个数据框和subj
中的第一个数字。我使用的匿名函数是function(x,y) {x[, "class"] <- y; x}
。它需要两个参数。第一个是数据框,第二个是列值。
现在前进更容易了。我们可以创建一个名为 uniq.nmes
的向量来获取我们将组合的数据帧的名称。其中 "A1"
将变为 "A"
。然后我们可以对该匹配进行 rbind:
uniq.nmes <- unique(sub("\d", "", names(lst)))
lapply(uniq.nmes, function(x) {
do.call(rbind, newlst[grep(x, names(newlst))])
})
# [[1]]
# x y class
# A1.1 1 79 1
# A1.2 30 13 1
# A2.1 90 39 2
# A2.2 43 22 2
#
# [[2]]
# x y class
# B1.1 54 59 1
# B1.2 83 90 1
# B2.1 85 36 2
# B2.2 91 28 2
数据
A1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
A2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
lst <- list(A1=A1,A2=A2,B1=B1,B2=B2)
听起来你在做很多体操,因为你有一个特定的形式。我建议首先尝试使数据 tidy。无需阅读 link,快速总结就是将您的数据放入单个数据框中,以便轻松处理。
答案的快速版本(这里我使用 lst
而不是 list
作为名称以避免与内置的 list
混淆)是这样做的:
do.call(rbind,
lapply(seq(lst), function(i) {
lst[[i]]$type <- names(lst)[i]; lst[[i]]
})
)
这将创建一个数据框,其中有一列 "type",其中包含出现该行的列表项的名称。
使用稍微简化的初始数据:
lst <- list(A1=data.frame(x=rnorm(5)), A2=data.frame(x=rnorm(3)), B=data.frame(x=rnorm(5)))
lst
$A1
x
1 1.3386071
2 1.9875317
3 0.4942179
4 -0.1803087
5 0.3094100
$A2
x
1 -0.3388195
2 1.1993115
3 1.9524970
$B
x
1 -0.1317882
2 -0.3383545
3 0.8864144
4 0.9241305
5 -0.8481927
然后应用魔法函数
df <- do.call(rbind,
lapply(seq(lst), function(i) {
lst[[i]]$type <- names(lst)[i]; lst[[i]]
})
)
df
x type
1 1.3386071 A1
2 1.9875317 A1
3 0.4942179 A1
4 -0.1803087 A1
5 0.3094100 A1
6 -0.3388195 A2
7 1.1993115 A2
8 1.9524970 A2
9 -0.1317882 B
10 -0.3383545 B
11 0.8864144 B
12 0.9241305 B
13 -0.8481927 B
从这里我们可以尽情地加工;使用 df$subject <- gsub("[0-9]*", "", df$type)
之类的操作来提取 type
的非数字部分,并且 split
之类的工具可用于生成您在问题中提到的子列表。
此外,一旦成为这种形式,您可以使用 by
和 aggregate
等函数或 dplyr
或 data.table
等库来进行更高级的拆分-应用合并操作进行数据分析。