逐行连接 data.table 中各列的名称和值
concatenate names and values across columns in data.table, row by row
与问题类似,我想连接列值的子集。但是,我还想在每个值前面加上列名,用“:”分隔名称和值,并控制用于分隔 name/value 对的字符。
例如,这给出了值的串联:
library(data.table)
d <- data.table(x = c(1, 2), y = c(3, 4))
labs_to_get <- c("x", "y")
d[
,
.(x, y, labs = do.call(paste, c(.SD, sep = ", "))),
.SDcols = labs_to_get
]
#> x y labs
#> 1: 1 3 1, 3
#> 2: 2 4 2, 4
但我正在寻找这个:
d[
,
.(x, y, labs = c("x: 1, y: 3", "x: 2, y: 4"))
]
#> x y labs
#> 1: 1 3 x: 1, y: 3
#> 2: 2 4 x: 2, y: 4
由 reprex package (v2.0.1)
于 2022-04-01 创建
我们可以paste
对应的名字Map
d[,
.(x, y, labs = do.call(paste, c(Map(function(u, v)
paste0(v, ": ", u), .SD, labs_to_get), sep = ", "))),
.SDcols = labs_to_get
]
-输出
x y labs
<num> <num> <char>
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
或者另一个选项是 write.dcf
d[, labs := do.call(paste,
c(as.list(setdiff(capture.output(write.dcf(.SD)), "")),
sep = ", ")), 1:nrow(d)]
> d
x y labs
<num> <num> <char>
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
或使用apply
遍历行
d[, labs := apply(.SD, 1, \(x) paste(names(x), x, sep = ": ",
collapse = ", ")), .SDcols = labs_to_get]
或使用tidyverse
library(dplyr)
library(purrr)
library(stringr)
d %>%
mutate(labs = invoke(str_c, c(across(all_of(labs_to_get),
~str_c(cur_column(), ": ", .x)), sep = ", ")))
x y labs
<num> <num> <char>
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
这是另一种 tidyverse
方法:
library(dplyr)
library(tidyr)
labs_to_get <- c("x", "y")
d %>%
mutate(across(everything(), ~case_when(cur_column() %in% labs_to_get ~ paste(cur_column(), ., sep = ": "))
, .names = 'new_{col}')) %>%
unite(labs, starts_with('new'), na.rm = TRUE, sep = ', ')
x y labs
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
怎么样:
d[,labs:=paste0(labs_to_get,":",c(.SD), collapse=", "), by=1:nrow(d), .SDcols=labs_to_get]
输出:
x y labs
<num> <num> <char>
1: 1 3 x:1, y:3
2: 2 4 x:2, y:4
与
例如,这给出了值的串联:
library(data.table)
d <- data.table(x = c(1, 2), y = c(3, 4))
labs_to_get <- c("x", "y")
d[
,
.(x, y, labs = do.call(paste, c(.SD, sep = ", "))),
.SDcols = labs_to_get
]
#> x y labs
#> 1: 1 3 1, 3
#> 2: 2 4 2, 4
但我正在寻找这个:
d[
,
.(x, y, labs = c("x: 1, y: 3", "x: 2, y: 4"))
]
#> x y labs
#> 1: 1 3 x: 1, y: 3
#> 2: 2 4 x: 2, y: 4
由 reprex package (v2.0.1)
于 2022-04-01 创建我们可以paste
对应的名字Map
d[,
.(x, y, labs = do.call(paste, c(Map(function(u, v)
paste0(v, ": ", u), .SD, labs_to_get), sep = ", "))),
.SDcols = labs_to_get
]
-输出
x y labs
<num> <num> <char>
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
或者另一个选项是 write.dcf
d[, labs := do.call(paste,
c(as.list(setdiff(capture.output(write.dcf(.SD)), "")),
sep = ", ")), 1:nrow(d)]
> d
x y labs
<num> <num> <char>
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
或使用apply
遍历行
d[, labs := apply(.SD, 1, \(x) paste(names(x), x, sep = ": ",
collapse = ", ")), .SDcols = labs_to_get]
或使用tidyverse
library(dplyr)
library(purrr)
library(stringr)
d %>%
mutate(labs = invoke(str_c, c(across(all_of(labs_to_get),
~str_c(cur_column(), ": ", .x)), sep = ", ")))
x y labs
<num> <num> <char>
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
这是另一种 tidyverse
方法:
library(dplyr)
library(tidyr)
labs_to_get <- c("x", "y")
d %>%
mutate(across(everything(), ~case_when(cur_column() %in% labs_to_get ~ paste(cur_column(), ., sep = ": "))
, .names = 'new_{col}')) %>%
unite(labs, starts_with('new'), na.rm = TRUE, sep = ', ')
x y labs
1: 1 3 x: 1, y: 3
2: 2 4 x: 2, y: 4
怎么样:
d[,labs:=paste0(labs_to_get,":",c(.SD), collapse=", "), by=1:nrow(d), .SDcols=labs_to_get]
输出:
x y labs
<num> <num> <char>
1: 1 3 x:1, y:3
2: 2 4 x:2, y:4