在R中将具有重复列名的宽数据框转换为长数据框

3
我正在尝试使用melt公式将数据框从宽格式转换为长格式。挑战在于我有多个列名标记相同。当我使用melt函数时,它会删除重复列的值。我已经阅读了类似的问题,并建议使用reshape函数,但我无法使其工作。
为了重现我的起始数据框:
conversion.id<-c("1", "2", "3")
interaction.num<-c("1","1","1")
interaction.num2<-c("2","2","2")
conversion.id<-as.data.frame(conversion.id)
interaction.num<-as.data.frame(interaction.num)
interaction.num2<-as.data.frame(interaction.num2)
conversion<-c(rep("1",3))
conversion<-as.data.frame(conversion)
df<-cbind(conversion.id,interaction.num, interaction.num2, conversion)
names(df)[3]<-"interaction.num"

数据框的样子如下:

enter image description here

当我运行以下的melt函数时:
melt.df<-melt(df,id="conversion.id")

它删除了interaction.num == 2列,并且看起来像这样:

enter image description here

我想要的数据框如下:

enter image description here

我看到了以下帖子,但我对reshape函数不太熟悉,无法使其正常运行。 如何使用“重复”列重新整理数据框? 并且为了增加一层复杂性,我正在寻找一种高效的方法。我需要在一个包含大量相同标签列的1M行数据框上执行此操作。
任何建议将不胜感激!
3个回答

3
以下是使用 tidyr 而不是 reshape2 的解决方案。其中一大优势是 gather_ 函数,它可以接受字符向量作为输入。因此,首先我们可以通过在每个名称末尾添加数字来替换所有“有问题”的变量名称并使其唯一,然后我们可以 gather (相当于 melt)这些特定变量。变量的唯一名称存储在一个名为“prob_var_name”的临时变量中,在最后我将其删除。
library(tidyr)
library(dplyr)

var_name <- "interaction.num"

problem_var <- df %>% 
  names %>% 
  equals(var_name) %>%
  which

replaced_names <- mapply(paste0,names(df)[problem_var],seq_along(problem_var))

names(df)[problem_var]  <- replaced_names

df %>%
  gather_("prob_var_name",var_name,replaced_names) %>%
  select(-prob_var_name)

  conversion.id conversion interaction.num
1             1          1               1
2             2          1               1
3             3          1               1
4             1          1               2
5             2          1               2
6             3          1               2

由于 gather_ 的引用能力,您可以将所有这些内容包装到一个函数中,并将 var_name 设置为变量。然后,您可以在所有重复的变量上使用它。

3

这里提供一个使用 data.table 的解决方案。您只需要提供索引而不是名称。

require(data.table)
require(reshape2)
ans <- melt(setDT(df), measure=2:3, 
           value.name="interaction.num")[, variable := NULL]

#    conversion.id conversion interaction.num
# 1:             1          1               1
# 2:             2          1               1
# 3:             3          1               1
# 4:             1          1               2
# 5:             2          1               2
# 6:             3          1               2

你可以通过执行grep("interaction.num", names(df))来获得索引2:3


1

这里是一种基于R语言的方法,应该适用于您:

x <- grep("interaction.num", names(df)) ## as suggested by Arun

## Make more friendly names for reshape
names(df)[x] <- paste(names(df)[x], seq_along(x), sep = "_")

## Reshape
reshape(df, direction = "long", 
        idvar=c("conversion.id", "conversion"), 
        varying = x, sep = "_")
#       conversion.id conversion time interaction.num
# 1.1.1             1          1    1               1
# 2.1.1             2          1    1               1
# 3.1.1             3          1    1               1
# 1.1.2             1          1    2               2
# 2.1.2             2          1    2               2
# 3.1.2             3          1    2               2

另一个可能性是使用stack而不是reshape
x <- grep("interaction.num", names(df)) ## as suggested by Arun
cbind(df[-x], stack(lapply(df[x], as.character)))

"

lapply(df[x], as.character)可能是不必要的,这取决于您的值是否实际上是数字。根据您创建此示例数据的方式,它们是factor

"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接