在 R 中使用 'separate'(tidyr) 拆分数据帧的几列



大家早上好,我读了几篇关于用R拆分列的文章,但我找不到如何解决我的问题。

我想使用tidyr R包中的"separate"函数,根据分隔符将数据帧的列分为两列。

我有这个数据帧:

dat1 AIN5997 AIN7452 AIN8674 AIN9655 001 01/02 02/02 02/02 01/02 002 01/02 01/01 02/02 02/02 003 01/02 01/02 01/01 02/02 004 01/02 01/01 02/02 01/02 005 01/01 01/01 02/02 02/02 006 01/02 01/02 01/01 02/02 ...

我想根据"/"将每列分为两列,如果可能的话,同时保留列名(例如:AIN5997将变为AIN5997.1和AIN5997.2)

我认为使用"separate"是可能的,但在尝试使用"apply"时,我无法将过程扩展到框架的每一列(可能是因为separate一次只能处理数据帧和一列)。这一定很容易,但我的R技能相当糟糕!

有许多线程解释如何将一列拆分为两列,如以下线程:将数据帧的一列拆分成多列

但我找不到如何同时扩展多个列的过程。

非常感谢你的帮助,

最好的:)

诀窍是按照正确的顺序创建新名称,因此请确保要分隔的列已提前排序。

NA值的问题在于进程无法拆分它们。所以,诀窍是用可以拆分的东西来替换它们。检查此项:

library(dplyr)
library(tidyr)
# example dataset
dt = data.frame(id = 1:2,
AIN5997  = c("01/02", "01/02"),
AIN7452  = c("02/02", NA),
AIN8674 = c("02/02","02/02"), stringsAsFactors = F)
# specify columns you want to separate (specify column positions)
input_names = names(dt)[2:4]
# create new names (you want each name twice)
new_names = expand.grid(input_names, 1:2) %>% 
unite(v, Var1, Var2, sep=".") %>% 
pull(v) %>% 
sort()
dt %>%
unite_("v", input_names) %>%                  # unite columns of interest
mutate(v = gsub("NA", "NA/NA", v)) %>%        # replace NAs with something that can be separated
separate(v, new_names, convert = F)           # separate elements and give new names
#   id AIN5997.1 AIN5997.2 AIN7452.1 AIN7452.2 AIN8674.1 AIN8674.2
# 1  1        01        02        02        02        02        02
# 2  2        01        02        NA        NA        02        02

我还添加了一个更好的解决方案。它自动处理NA值,您不必担心列名及其顺序。

library(dplyr)
library(tidyr)
library(purrr)
# example dataset
dt = data.frame(id = 1:2,
AIN5997  = c("01/02", "01/02"),
AIN7452  = c("02/02", NA),
AIN8674 = c("02/02","02/02"), stringsAsFactors = F)
# separate a given column of your initial dataset
f = function(x) { dt %>% select_("id", x) %>% separate_(x, paste0(x, c(".1",".2"))) }

names(dt)[2:4] %>%             # get names of columns you want to separate
map(f) %>%                   # apply the function above to each name (will create a list of dataframes)
reduce(left_join, by="id")   # join dataframes iteratively
#   id AIN5997.1 AIN5997.2 AIN7452.1 AIN7452.2 AIN8674.1 AIN8674.2
# 1  1        01        02        02        02        02        02
# 2  2        01        02      <NA>      <NA>        02        02

您也可以使用tstrsplit()

# example dataset
df <- data.frame(AIN5997  = c("01/02", "01/02"),
AIN7452  = c("02/02","01/01"),
AIN8674 = c("02/02","02/02"), stringsAsFactors = F)
df
df2 <- as.data.frame(unlist(lapply(df, data.table::tstrsplit, "/"),
recursive = FALSE))
df2
colnames(df2) # change colnames
colnames(df2) <- paste(substr(colnames(df2), 1, nchar(colnames(df2))-1),
substr(colnames(df2), nchar(colnames(df2)), nchar(colnames(df2))),
sep = ".")
df2