separate_wideer,其中前半部分为列名,后半部分为单元格值

czq61nw1  于 2023-03-15  发布在  其他
关注(0)|答案(4)|浏览(130)
df <- data.frame(V_1 = c("null", "name:c", "name:d", "name:a", "name:k","name:A"),
                 V_2 = c("null", "cat:Y", "cat:Z", "cat:K", "cat:L","cat:K"))

我有一个包含多个列的 Dataframe ,这些列具有如上所述的键-值对。
我希望分隔单元格的值,这样“key”就成为新列的列名,“value”就成为单元格的值。
预期产出:

df2 <- data.frame(name = c("null", "c", "d", "a", "k","A"),
                  cat = c("null", "Y", "Z", "K", "L","K"))
df2

注意,对于我的真实的 Dataframe ,我有几百个列,所以我正在寻找一种解决方案,它不需要手动键入列名称,而是基于键:值对的前半部分自动生成名称。
目前,我使用以下方法拆分键-值对:

df3 <- df %>%
  separate_wider_delim(cols = everything(),
                       delim = ",",
                       too_few = "align_start",
                       names_sep = "")

但是我不知道如何正确地转换它,使分隔值的前半部分成为列名。

vqlkdk9b

vqlkdk9b1#

在Base R中,您可以在粘贴所有内容后使用read.dcf

a <- do.call(paste, c(sep="\n", collapse = "\n\n", df))
read.dcf(textConnection(a), all = TRUE)

  name cat
1    B   X
2    c   Y
3    d   Z
4    a   K
5    k   L
6    A   K

编辑

setNames(data.frame(sub(".*:","", as.matrix(df))),gsub("(\\w+):.*|.", "\\1", df))
  name  cat
1 null null
2    c    Y
3    d    Z
4    a    K
5    k    L
6    A    K
yeotifhr

yeotifhr2#

您可以使用第一行来获取列名,删除冒号之后的所有内容。
要清除列值,请删除冒号之前的所有内容。

names(df) <- sub(':.*', '', unlist(df[1,]))
df[] <- lapply(df, function(x) sub('.*:', '', x))
df

#  name cat
#1    B   X
#2    c   Y
#3    d   Z
#4    a   K
#5    k   L
#6    A   K

第二步也可以使用dplyr-

library(dplyr)
df <- df %>% mutate(across(everything(), ~sub('.*:', '', .)))
tp5buhyn

tp5buhyn3#

您不必总是尝试将所有内容压缩到一个步骤中,使用更传统的工具,两个不同的步骤也可以很好地工作:

get_col_names <- function(col){
  col_split <- stringr::str_split(string = col[1],pattern = ":")
  col_split[[1]][1]
}

new_cn <- sapply(df,get_col_names)
> df %>%
+   mutate(
+     across(.cols = everything(),
+            .fns = ~gsub("^.*:","",.x))
+     ) %>%
+   set_names(nm = new_cn)
  name cat
1    B   X
2    c   Y
3    d   Z
4    a   K
5    k   L
6    A   K
fnx2tebb

fnx2tebb4#

下面是一个tidyverse解决方案:第二部分也由@Ronak Shah提供:

library(dplyr)
library(tidyr)

my_names <- df %>% 
  filter(if_any(everything(), ~.!="null")) %>% 
  pivot_longer(everything()) %>% 
  separate(value, into = c("a", "b")) %>% 
  pull(a) %>% 

df %>% 
  rename_with(~unique(my_names)) %>% 
  mutate(across(everything(), ~sub('.*:', '', .)))
name  cat
1 null null
2    c    Y
3    d    Z
4    a    K
5    k    L
6    A    K

相关问题