r-将列与变量名称的大写和非大写版本合并,而不指定变量名称

  • 本文关键字:变量名 合并 版本 r data.table
  • 更新时间 :
  • 英文 :


我有一个(大(数据帧,如下所示:

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)

我只想合并变量Aa,以及Bb

编辑:问题是我必须对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_longerpivot_widerspreadgather的首选替代方案。

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[]
lc                 V1
1:  a Coalesced a onto A
2:  b Coalesced b onto B
D_8

对于另一个用例

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)

以上代码返回

lc                       V1
1:  a       Coalesced a onto A
2:  b       Coalesced b onto B
3: cc Coalesced cc, cC onto CC
D_12

解释

  1. 列名被转换为data.table,其中包含一列小写版本的列名的附加列lc
  2. 代替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

最新更新