在R中比较多个CSV文件的列名

lsmepo6l  于 2023-03-27  发布在  其他
关注(0)|答案(2)|浏览(145)

我在R中将12个CSV文件合并到一个数据框中。在此之前,我想确保所有的列名彼此完全匹配。我已经制作了一个数据框,其中每一列都是12个CSV文件的列名。

jul21_cols <- data.frame(colnames(jul21))
aug21_cols <- data.frame(colnames(aug21))
sep21_cols <- data.frame(colnames(sep21))
oct21_cols <- data.frame(colnames(oct21))
nov21_cols <- data.frame(colnames(nov21))
dec21_cols <- data.frame(colnames(dec21))
jan22_cols <- data.frame(colnames(jan22))
feb22_cols <- data.frame(colnames(feb22))
mar22_cols <- data.frame(colnames(mar22))
apr22_cols <- data.frame(colnames(apr22))
may22_cols <- data.frame(colnames(may22))
jun22_cols <- data.frame(colnames(jun22))

col_df <- cbind(jul21_cols,aug21_cols,sep21_cols,oct21_cols,nov21_cols,dec21_cols,
                 jan22_cols,feb22_cols,mar22_cols,apr22_cols,may22_cols,jun22_cols)

我尝试使用相同的函数一次比较2列。

identical(col_df[['jul21']], col_df[['aug21']])
identical(col_df[['aug21']], col_df[['sep21']])
identical(col_df[['sep21']], col_df[['oct21']])
identical(col_df[['oct21']], col_df[['nov21']])
identical(col_df[['nov21']], col_df[['dec21']])
identical(col_df[['dec21']], col_df[['jan22']])
identical(col_df[['jan22']], col_df[['feb22']])
identical(col_df[['feb22']], col_df[['mar22']])
identical(col_df[['mar22']], col_df[['apr22']])
identical(col_df[['apr22']], col_df[['may22']])
identical(col_df[['may22']], col_df[['jun22']])`

所有相同的行都返回TRUE值
我只是想在继续之前验证这段代码是否告诉我每个CSV文件中的所有列名都是相同的。我还想知道是否有更有效的方法来解决这个问题。

z4bn682m

z4bn682m1#

首先,identical()只会在两个 Dataframe 有相同的列名 * 且顺序相同的情况下返回TRUE。* 如果你不关心顺序,只是在两个 Dataframe 中有相同的名称,你可以在比较之前sort()名称,如下所示。
其次,您可以经常使用base::lapply()purrr::map()函数族来进行需要迭代的操作。
对于您的情况,让我们将 Dataframe 放在一个列表(which they probably should be to begin with)中,然后使用sapply()将列表中第一个df的列名与所有其他df的列名进行比较。

jul21 <- data.frame(x = 1, y = 2)
aug21 <- data.frame(x = 3, y = 4) 
sep21 <- data.frame(y = 6, x = 5)

dfs <- list(jul21,aug21,sep21)

all(sapply(
  dfs[-1], 
  \(x) identical(sort(colnames(x)), sort(colnames(dfs[[1]])))
))
# TRUE

作为另一个测试用例,我们将添加一个带有非匹配列的df。

oct22 <- data.frame(x = 1, y = 2, z = 3)
dfs[[4]] <- oct22

all(sapply(
  dfs[-1], 
  \(x) identical(sort(colnames(x)), sort(colnames(dfs[[1]])))
))
# FALSE
zfycwa2u

zfycwa2u2#

我们假设需要确定列名是否相同且顺序相同,如果不相同,则确定哪些不同。
首先获取一个字符向量Names,它包含 Dataframe 的名称,并从中创建一个包含 Dataframe 本身的命名列表L。
从这些名称中组装 Dataframe 的列表L,然后得到特征向量nms,其元素是列名的字符串,每个 Dataframe 一个。
最后,使用tapply和nms作为分组来对 Dataframe 的名称进行分组,这样我们就可以看到哪些 Dataframe 包含哪些列。在下面的示例中,aug21和jul21具有一组列,即Time和demand,而sep21具有不同的一组,即Time和DEMAND。如果只有一行,则所有 Dataframe 都具有相同顺序的相同列名。

Names <- c("jul21", "aug21", "sep21") # using example in Note

L <- mget(Names)[Names]

nms <- sapply(names(L), function(x) toString(names(L[[x]])))
tab <- stack(tapply(names(nms), nms, toString))
names(tab) <- c("data.frames", "column.names")

nrow(tab)
## [1] 2

tab
##    data.frames column.names
## 1 jul21, aug21 Time, demand
## 2        sep21 Time, DEMAND

另一种可以与上述方法交替使用或结合使用的方法是创建一个图,使得每个顶点都是一个数据框,并且每个边意味着边两端的两个顶点具有相同顺序的相同列名。从下面的例子中,我们可以看到jul21和aug21形成一个连通分量,sep21形成第二个连通分量。
要研究 Dataframe 列名的不同之处,请注意setdiff(names(jul21), names(sep21))将显示7月21日而不是9月21日的名称,反之可用于另一个方向。如果两个方向的setdiff都是零长度向量,并且名称向量不相同,则它们按顺序不同。

library(igraph)
set.seed(123)

isSame <- function(x, y) +identical(names(x), names(y))
A <- outer(L, L, Vectorize(isSame))
diag(A) <- 0

g <- graph_from_adjacency_matrix(A, "undirected")
plot(g, vertex.color = "white", vertex.size = 30)

注解

测试数据。生化需氧量随R。

jul21 <- aug21 <- sep21 <- BOD
names(sep21) <- c("Time", "DEMAND")

相关问题