在组内重塑数据 - 一行中的组

Reshape data within groups - groups in a single row

这是我的输入数据:

 DeviceID   ContentID   Use
 D1 C1  0.678491346
 D1 C2  0.302147374
 D2 C1  0.695790066
 D2 C2  0.645849165
 D3 C1  0.83503997
 D3 C2  0.3622916

预期输出:

DeviceID    ContentID_1 Use_1   ContentID_2 Use_2
D1  C1  0.678491346 C2  0.302147374
D2  C1  0.695790066 C2  0.645849165
D3  C1  0.83503997  C2  0.3622916

我尝试使用 reshape2 重塑它,但无法获得所需格式。

我试过了:

 df %>% 
   group_by(DeviceID) %>% 
   mutate(rn = paste0("Content",row_number())) %>% 
   spread(rn, Use)

dcast(df,
      DeviceID~ContentID,
      value.var ="Use")

如有任何帮助,我们将不胜感激!

我们可以使用Reduceaggregate按照上面给出的格式重新排列

data.frame(Reduce(cbind,aggregate(.~Device,dat,I)))[c(1,2,4,3,5)]
  init V2          V4 V3          V5
1   D1 C1 0.678491346 C2 0.302147374
2   D2 C1 0.695790066 C2 0.645849165
3   D3 C1  0.83503997 C2   0.3622916

这是库 dplyr 的蛮力

 map2_dfc(s<-dat%>%spread(Id,Content),names(s),~rev(stack(s,.y)))
     ind values ind1   values1 ind2   values2
1 Device     D1   C1 0.6784913   C2 0.3021474
2 Device     D2   C1 0.6957901   C2 0.6458492
3 Device     D3   C1 0.8350400   C2 0.3622916
df = read.table(text = "
DeviceId  ContentID  Use
D1 C1  0.678491346
D1 C2  0.302147374
D2 C1  0.695790066
D2 C2  0.645849165
D3 C1  0.83503997
D3 C2  0.3622916
", header=T, stringsAsFactors=F)

library(tidyverse)

df %>%
  group_by(DeviceId) %>%
  summarise_all(function(x) paste0(x, collapse = "_")) %>%
  separate(ContentID, c("ID_1","ID_2"), sep="_") %>%
  separate(Use, c("Use_1","Use_2"), sep="_")

# # A tibble: 3 x 5
#   DeviceId ID_1  ID_2  Use_1       Use_2      
# * <chr>    <chr> <chr> <chr>       <chr>      
# 1 D1       C1    C2    0.678491346 0.302147374
# 2 D2       C1    C2    0.695790066 0.645849165
# 3 D3       C1    C2    0.83503997  0.3622916 

发布我的解决方案:

library(splitstackshape)
library(tidyverse)

df %>%
  group_by(DeviceId) %>%
  summarise_all(function(x) paste0(x, collapse = "_")) %>%
  cSplit(names(.)[-1], '_')

在评论中包含@AntoniosK 的建议。

library(data.table)
DT <- setDT(df)

使用您的 dcast 意图,您可以做到

    Reduce(function(dtf1,dtf2) merge(dtf1,dtf2, by = "DeviceId"), 
           lapply( unique(DT$ContentID),
                   function(x){dcast(DT[ContentID == x],DeviceId + ContentID  ~ ContentID ,value.var = "Use")} ))

   DeviceId ContentID.x        C1 ContentID.y        C2
1:       D1          C1 0.6784913          C2 0.3021474
2:       D2          C1 0.6957901          C2 0.6458492
3:       D3          C1 0.8350400          C2 0.3622916

自 v1.9.6(2015 年 9 月 19 日 CRAN)起,data.table 可以同时转换多个值列:

library(data.table)
dcast(setDT(df), DeviceID ~ rowid(DeviceID), value.var = c("ContentID", "Use"))
    DeviceID  ContentID_1  ContentID_2     Use_1     Use_2
1:        D1           C1           C2 0.6784913 0.3021474
2:        D2           C1           C2 0.6957901 0.6458492
3:        D3           C1           C2 0.8350400 0.3622916

更改列顺序

结果包含预期的列,但顺序不同。 dcast() 创建按 value.var 分组的新列。

OP 没有指出确切的列顺序是否重要。但是,可以通过引用 更改列顺序 来准确重现预期结果,即,无需使用 setcolorder():

复制整个数据对象
cols <- c("ContentID", "Use")
wide <- dcast(setDT(df), DeviceID ~ rowid(DeviceID), value.var = cols)
new_col_order <- CJ(seq_len(uniqueN(df$ContentID)), cols)[, paste(V2, V1, sep = "_")]
setcolorder(wide, new_col_order)
wide
   ContentID_1     Use_1 ContentID_2     Use_2 DeviceID
1:          C1 0.6784913          C2 0.3021474       D1
2:          C1 0.6957901          C2 0.6458492       D2
3:          C1 0.8350400          C2 0.3622916       D3

CJ() 是行 ID 与 value.vars 的交叉连接,以按所需顺序创建列名。

我已提交 feature request on GitHub 以选择性地更改 dcast() 中列的顺序。

数据

library(data.table)
df <- fread(
  " DeviceID  ContentID  Use
 D1 C1  0.678491346
  D1 C2  0.302147374
  D2 C1  0.695790066
  D2 C2  0.645849165
  D3 C1  0.83503997
  D3 C2  0.3622916"
)