我有一个600多个数据帧的列表,这些数据帧没有完全相同的结构(列名,列的顺序和变量的类型)。我需要做的是识别出那些数据框中哪些没有所需的结构并对其进行修改,以便我可以将所有数据用于不同的目的(汇总,分析等)。
我试图根据所需的名称和列顺序从主列表创建两个列表。为此,我尝试执行以下操作:
# some random dfs for the example
v1 <- c(1:15)
v2 <- c(20:34)
v3 <- c("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o")
v3b <- c("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o")
df1 <- data.frame(v1, v2, v3)
df2 <- data.frame(v1, v2, v3)
df3 <- data.frame(v1, v2, v3b)
mylist <- list(df1, df2, df3)
names <- colnames(mylist[[1]]) #remember I have over 600 dfs in the original list
listA <- list()
listB <- list()
#I suppose this piece of code should work
colnames(mylist[[1]]) == names
colnames(mylist[[2]]) == names
colnames(mylist[[3]]) == names
for (k in 1:length(mylist)){
if(colnames(mylist[[k]]) == names){
listA[[k]] <- mylist[[k]]
}else{
listB[[k]] <- mylist[[k]]
}
}
现在的问题是,带有条件语句的循环会生成一个包含所有数据帧的列表和另一个空列表。它还会生成以下警告:
1:如果if(colnames(mylist [[k]])==名称){: 条件的长度> 1,并且只会使用第一个元素
我已经阅读并在堆栈流中查找了大量内容来解决此问题,但我感到束手无策...
有人知道代码有什么问题吗? 更重要的是,这是否是一种适当的方法来根据姓氏拆分我的数据帧列表,或者有更好的名字?
答案 0 :(得分:1)
您可以使用identical
而不是==
来更正方法,如果您不希望使用k
元素,也应该修复NULL
索引:
for (k in 1:length(mylist)){
if(identical(colnames(mylist[[k]]), names)){
listA[[length(listA)+1]] <- mylist[[k]]
}else{
listB[[length(listB)+1]] <- mylist[[k]]
}
}
我宁愿使用split,这是一个建议:
split(mylist,sapply(mylist,function(x) identical(colnames(x),names)))
$`FALSE`
$`FALSE`[[1]]
v1 v2 v3b
1 1 20 a
2 2 21 b
3 3 22 c
4 4 23 d
5 5 24 e
6 6 25 f
7 7 26 g
8 8 27 h
9 9 28 i
10 10 29 j
11 11 30 k
12 12 31 l
13 13 32 m
14 14 33 n
15 15 34 o
$`TRUE`
$`TRUE`[[1]]
v1 v2 v3
1 1 20 a
2 2 21 b
3 3 22 c
4 4 23 d
5 5 24 e
6 6 25 f
7 7 26 g
8 8 27 h
9 9 28 i
10 10 29 j
11 11 30 k
12 12 31 l
13 13 32 m
14 14 33 n
15 15 34 o
$`TRUE`[[2]]
v1 v2 v3
1 1 20 a
2 2 21 b
3 3 22 c
4 4 23 d
5 5 24 e
6 6 25 f
7 7 26 g
8 8 27 h
9 9 28 i
10 10 29 j
11 11 30 k
12 12 31 l
13 13 32 m
14 14 33 n
15 15 34 o
答案 1 :(得分:1)
通过将名称与match()
匹配,然后使用split()
来创建您要获得的组。
f <- sapply(mylist, function(x) length(na.omit(match(names(x), names))))
listNew <- setNames(split(mylist, f), c("listB", "listA"))
屈服
> str(listNew)
List of 2
$ listB:List of 1
..$ :'data.frame': 15 obs. of 3 variables:
.. ..$ v1 : int [1:15] 1 2 3 4 5 6 7 8 9 10 ...
.. ..$ v2 : int [1:15] 20 21 22 23 24 25 26 27 28 29 ...
.. ..$ v3b: Factor w/ 15 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ...
$ listA:List of 2
..$ :'data.frame': 15 obs. of 3 variables:
.. ..$ v1: int [1:15] 1 2 3 4 5 6 7 8 9 10 ...
.. ..$ v2: int [1:15] 20 21 22 23 24 25 26 27 28 29 ...
.. ..$ v3: Factor w/ 15 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ...
..$ :'data.frame': 15 obs. of 3 variables:
.. ..$ v1: int [1:15] 1 2 3 4 5 6 7 8 9 10 ...
.. ..$ v2: int [1:15] 20 21 22 23 24 25 26 27 28 29 ...
.. ..$ v3: Factor w/ 15 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ...
答案 2 :(得分:0)
如果我正确理解了您想要的内容,则以下代码将原始列表分为两个列表:
listA
具有名称等于mylist[[1]]
的所有数据框; listB
具有所有其他数据框。它使用*apply
函数而不是显式的for
循环。
nms <- lapply(mylist, names)
inx <- sapply(nms[-1], function(nm) all(nm == nms[[1]]))
inx <- c(TRUE, inx)
listA <- mylist[inx]
listB <- mylist[!inx]
答案 3 :(得分:0)
这是一个tidyverse
解决方案,定义时使用mylist
和names
:
library(tidyverse)
listA <-
mylist %>%
keep(~ all(names(.) %in% names)
listB <-
mylist %>%
discard(~ all(names(.) %in% names)