我有一个(大(数据帧,如下所示:
library(data.table)
DT <- fread(
"ID country year A b B a
4 NLD 2002 NA 1 NA 0
5 NLD 2002 NA 0 NA 1
6 NLD 2006 NA 1 NA 1
7 NLD 2006 NA 0 NA 0
8 NLD 2006 0 NA 0 NA
9 GBR 2002 0 NA 0 NA
10 GBR 2002 0 NA 0 NA
11 GBR 2002 0 NA 0 NA
12 GBR 2006 1 NA 1 NA
13 GBR 2006 1 NA 0 NA",
header = TRUE)
我只想合并变量A
和a
,以及B
和b
。
编辑:问题是我必须对1000多个变量执行此操作,所以我希望避免指定不需要检查的列名或需要检查的列。
我希望有一个解决方案,首先将列拆分为一个没有非资本化替代方案的组和一个有的组。
据我所知,这里的解决方案是:
R 中基于模式的聚结柱
它仍然需要提供需要检查案例的变量名称。如果我误解了这个很有可能的解决方案,请告诉我。在任何情况下,正如所解释的,我都需要一个没有具体指定变量的解决方案。
我在这里找到了一个良好的开端。
然而,这个解决方案与我需要的方法略有不同。
如何使这样的变量merge以tolower(varname) == varname
为条件?
期望输出:
DT <- fread(
"ID country year A B
4 NLD 2002 0 1
5 NLD 2002 1 0
6 NLD 2006 1 1
7 NLD 2006 0 0
8 NLD 2006 0 0
9 GBR 2002 0 0
10 GBR 2002 0 0
11 GBR 2002 0 0
12 GBR 2006 1 1
13 GBR 2006 1 0 ",
header = TRUE)
我可以使用tidyverse函数提供一个解决方案。这与AntoniosK提供的解决方案基本相同,但pivot_longer
和pivot_wider
是spread
和gather
的首选替代方案。
library(dplyr)
library(tidyr)
DT %>%
mutate(UNIQUEID = row_number()) %>%
mutate_all(as.character) %>%
pivot_longer(cols = -UNIQUEID) %>%
mutate(name = stringr::str_to_upper(name)) %>%
filter(!is.na(value)) %>%
pivot_wider(names_from = name, values_from = value) %>%
type.convert(as.is=TRUE) %>% select(-UNIQUEID)
h/t@dario的伟大建议。
仅限data.table
的解决方案-使用简单的循环而不是重塑数据:
all_cols <- names(DT)
cols <- grep("[A-Z]", all_cols, value = TRUE)
for (col in cols) {
snc <- all_cols[all_cols == tolower(col)]
if (length(snc)) {
DT[, (col) := fcoalesce(.SD), .SDcols = c(snc, col)]
DT[, (setdiff(snc, col)) := NULL]
}
}
> DT[]
ID country year A B
1: 4 NLD 2002 0 1
2: 5 NLD 2002 1 0
3: 6 NLD 2006 1 1
4: 7 NLD 2006 0 0
5: 8 NLD 2006 0 0
6: 9 GBR 2002 0 0
7: 10 GBR 2002 0 0
8: 11 GBR 2002 0 0
9: 12 GBR 2006 1 1
10: 13 GBR 2006 1 0
OP正在使用data.table
,因此该问题应该得到data.table
的答案。
下面的方法与sindri_baldur的答案大体相似,但在重要细节上有所不同。特别是
- 它还将合并多个列,如
"CC", "cc", "cC"
,涵盖不同的变量名书写方式,例如,大写、小写,以及小写和大写camel - 它将返回已合并的列的描述
library(data.table)
library(magrittr) # piping is used to improve readability
names(DT) %>%
data.table(orig = ., lc = tolower(.)) %>%
.[, {
if (.N > 1L) {
new <- toupper(.BY)
old <- setdiff(orig, new)
DT[, (new) := fcoalesce(.SD), .SDcols = orig]
DT[, (old) := NULL]
sprintf("Coalesced %s onto %s", toString(old), new)
}
}, by = lc]
DT[]
D_8lc V1 1: a Coalesced a onto A 2: b Coalesced b onto B
对于另一个用例
DT2 <- fread(
"ID country year A b B a CC cc cC
4 NLD 2002 NA 1 NA 0 1 NA NA
5 NLD 2002 NA 0 NA 1 NA 2 NA
6 NLD 2006 NA 1 NA 1 NA NA 3
7 NLD 2006 NA 0 NA 0 NA NA NA
8 NLD 2006 0 NA 0 NA 1 NA NA
9 GBR 2002 0 NA 0 NA NA 2 NA
10 GBR 2002 0 NA 0 NA NA NA 3
11 GBR 2002 0 NA 0 NA 1 NA NA
12 GBR 2006 1 NA 1 NA NA 2 NA
13 GBR 2006 1 NA 0 NA NA NA 3",
header = TRUE)
DT <- copy(DT2)
以上代码返回
D_12lc V1 1: a Coalesced a onto A 2: b Coalesced b onto B 3: cc Coalesced cc, cC onto CC
解释
- 列名被转换为data.table,其中包含一列小写版本的列名的附加列
lc
- 代替
for
循环,我们使用分组by =
和data.table
的特征来评估任何表达,即使有副作用。因此,对于在步骤1中动态创建的data.table
的范围内的lc
的每个不同值,通过引用来更新DT
,但仅当组中有多个列时
未来的扩展
这种方法可以扩展到合并在列名中使用下划线、点或空格"_", ".", " "
的列,例如"var_1", "VAR.1", "Var 1"
。
假设您的示例数据集代表您的一般情况,这应该有效:
library(data.table)
library(tidyverse)
DT <- fread(
"ID country year A b B a
4 NLD 2002 NA 1 NA 0
5 NLD 2002 NA 0 NA 1
6 NLD 2006 NA 1 NA 1
7 NLD 2006 NA 0 NA 0
8 NLD 2006 0 NA 0 NA
9 GBR 2002 0 NA 0 NA
10 GBR 2002 0 NA 0 NA
11 GBR 2002 0 NA 0 NA
12 GBR 2006 1 NA 1 NA
13 GBR 2006 1 NA 0 NA",
header = TRUE)
# spot the column names to keep as they are
data.frame(x = names(DT), stringsAsFactors = F) %>% # get actual column names of the dataset
mutate(y = toupper(x)) %>% # get the upper values
group_by(y) %>% # for each upper value
filter(n() == 1) %>% # count them and keep only the unique columns
pull(x) -> fix_cols # store unique column names
DT %>%
gather(col_name, value, -fix_cols) %>% # reshape dataset
mutate(col_name = toupper(col_name)) %>% # change column names to upper case
na.omit() %>% # remove NA rows
spread(col_name, value) # reshape again
# ID country year A B
# 1 4 NLD 2002 0 1
# 2 5 NLD 2002 1 0
# 3 6 NLD 2006 1 1
# 4 7 NLD 2006 0 0
# 5 8 NLD 2006 0 0
# 6 9 GBR 2002 0 0
# 7 10 GBR 2002 0 0
# 8 11 GBR 2002 0 0
# 9 12 GBR 2006 1 1
# 10 13 GBR 2006 1 0