3

我正在尝试使用融化公式将数据帧从宽格式转换为长格式。挑战在于我有多个标记相同的列名。当我使用 melt 函数时,它会从重复列中删除值。我读过类似的问题,建议使用重塑功能,但我无法让它工作。

要重现我的起始数据框:

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"

数据框如下所示:

在此处输入图像描述

当我运行以下融化功能时:

melt.df<-melt(df,id="conversion.id")

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

在此处输入图像描述

我想要的数据框如下:

在此处输入图像描述

我看到了下面的帖子,但我对重塑功能不太熟悉,无法让它工作。

如何用“重复出现”的列重塑数据框?

为了增加一层复杂性,我正在寻找一种有效的方法。我需要在大约 1M 行的数据框中执行此操作,其中许多列标记相同。

任何建议将不胜感激!

4

3 回答 3

3

这是使用tidyr代替的解决方案reshape2。优点之一是gather_函数,它将字符向量作为输入。因此,首先我们可以用唯一的名称替换所有“有问题的”变量名称(通过在每个名称的末尾添加数字),然后我们可以收集(相当于融化)这些特定变量。变量的唯一名称存储在一个名为“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为一个变量。那么也许你可以在所有重复的变量上使用它?

于 2014-06-20T21:18:52.507 回答
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

2:3你可以通过做得到索引grep("interaction.num", names(df))

于 2014-06-20T22:42:37.747 回答
1

这是base 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)可能不是必需的。您创建此示例数据的方式是factors。

于 2014-06-27T16:59:58.073 回答