6

我是 R 新手/可以选择轻松地重新组织数据,并且一直在寻找解决方案,但找不到我想要做的事情。Reshape2 的熔化/铸造似乎不太奏效,而且我对 plyr 的掌握还不够好,无法将其考虑在内。

基本上我有一个具有下面概述的结构的data.frame,其中每个元素都是一个可变长度的类别列表(更紧凑,因为# 列更大,我实际上有多个我想要的category_lists喜欢分开):

>mydf
       ID      category_list    xval    yval
1     ID1   cat1, cat2, cat3   xnum1   ynum1
2     ID2         cat2, cat3   xnum2   ynum2
3     ID3               cat1   xnum3   ynum3

我想将类别作为因素(以及相关的值,即第 3/4 列)进行操作,所以我认为我最终需要这样的东西,其中 ID 和 x/y/其他列值根据类别列表的长度:

       ID           category    xval    yval
1     ID1               cat1   xnum1   ynum1
2     ID1               cat2   xnum1   ynum1
3     ID1               cat3   xnum1   ynum1
4     ID2               cat2   xnum2   ynum2
5     ID2               cat3   xnum2   ynum2
6     ID3               cat3   xnum2   ynum2

如果 category_list 上的因子/方面有另一个解决方案,那将是一个更简单的解决方案,但我没有遇到支持此的方法,例如以下引发错误

>ggplot(mydf, aes(x=x, y=y)) + geom_point() + facet_grid(~cat_list)

layout_base(data, cols, drop = drop) 中的错误:至少一层必须包含用于分面的所有变量

谢谢!

4

6 回答 6

9

答案将取决于category_list. 如果实际上它是list每一行的

就像是

mydf <- data.frame(ID = paste0('ID',1:3), 
 category_list = I(list(c('cat1','cat2','cat3'),  c('cat2','cat3'), c('cat1'))), 
 xval = 1:3, yval = 1:3)

或者

library(data.table)
mydf <- as.data.frame(data.table(ID = paste0('ID',1:3), 
 category_list = list(c('cat1','cat2','cat3'),  c('cat2','cat3'), c('cat1')), 
 xval = 1:3, yval = 1:3) )

然后你可以使用plyrandmerge来创建你的长表单数据

 newdf <- merge(mydf, ddply(mydf, .(ID), summarize, cat_list = unlist(category_list)), by = 'ID')


   ID    category_list xval yval cat_list
1 ID1 cat1, cat2, cat3    1    1     cat1
2 ID1 cat1, cat2, cat3    1    1     cat2
3 ID1 cat1, cat2, cat3    1    1     cat3
4 ID2       cat2, cat3    2    2     cat2
5 ID2       cat2, cat3    2    2     cat3
6 ID3             cat1    3    3     cat1

或不需要的非 plyr 方法merge

 do.call(rbind,lapply(split(mydf, mydf$ID), transform, cat_list = unlist(category_list)))
于 2013-01-09T01:03:26.143 回答
5

一个缓慢但看似强大的解决方案:

## Some example data
df <- as.data.frame(cbind(ID = paste0("ID", 1:2), 
                          category_list = list(4:1, 2:3), 
                          xvar = 8:9, 
                          yvar = 10:9))

## Calculate number of times each row of df will be repeated 
nn <- sapply(df$category_list, length)  
ii <- rep(seq_along(nn), times=nn)       

## Reshape data.frame
transform(df[ii,], 
          category = unlist(df$category_list),
          category_list = NULL, 
          row.names = NULL)
#    ID xvar yvar category
# 1 ID1    8   10        4
# 2 ID1    8   10        3
# 3 ID1    8   10        2
# 4 ID1    8   10        1
# 5 ID2    9    9        2
# 6 ID2    9    9        3
于 2013-01-09T00:56:50.490 回答
2

一个潜在可能:

x <- read.table(textConnection('
    ID      category_list    xval    yval
     ID1   "cat1, cat2, cat3"   xnum1   ynum1
     ID2         "cat2, cat3"   xnum2   ynum2
     ID3               "cat1"   xnum3   ynum3'),
          header=TRUE,stringsAsFactors=FALSE)

library(plyr)
ddply(x,"ID",transform,category=strsplit(category_list,",")[[1]])

##    ID    category_list  xval  yval category
## 1 ID1 cat1, cat2, cat3 xnum1 ynum1     cat1
## 2 ID1 cat1, cat2, cat3 xnum1 ynum1     cat2
## 3 ID1 cat1, cat2, cat3 xnum1 ynum1     cat3
## 4 ID2       cat2, cat3 xnum2 ynum2     cat2
## 5 ID2       cat2, cat3 xnum2 ynum2     cat3
于 2013-01-09T00:52:38.910 回答
0

这将是一种非 plyr 方法:

cbind( x[ rep(1:nrow(x), 
              times=sapply(x$category_list, 
                            function(xx) sapply( strsplit(xx, ","), length) ) ),
          -2],    # to get rid of the old category column
       new_cats = unlist( strsplit(x$category_list, ",") ) )
 # this used Bolker's example. If these are factor will need to add `as.character`

     ID  xval  yval new_cats
1   ID1 xnum1 ynum1     cat1
1.1 ID1 xnum1 ynum1     cat2
1.2 ID1 xnum1 ynum1     cat3
2   ID2 xnum2 ynum2     cat2
2.1 ID2 xnum2 ynum2     cat3
3   ID3 xnum3 ynum3     cat1
于 2013-01-09T01:10:26.973 回答
0

使用 的另一种基本 R 可能性by

do.call(rbind,
by(mydf,
   mydf$ID,
   function(x) {
     data.frame(
                ID=x$ID,
                category_list = unlist(strsplit(x$category_list,",")),
                xval=x$xval,
                yval=x$yval
               ) 
   }
  )
)

结果:

       ID category_list  xval  yval
ID1.1 ID1          cat1 xnum1 ynum1
ID1.2 ID1          cat2 xnum1 ynum1
ID1.3 ID1          cat3 xnum1 ynum1
ID2.1 ID2          cat2 xnum2 ynum2
ID2.2 ID2          cat3 xnum2 ynum2
ID3   ID3          cat1 xnum3 ynum3
于 2013-01-09T01:35:26.913 回答
0

注意:原始答案已删除,因为我的答案基于与 OP 实际拥有的数据结构不同的数据结构。


场景 1:列是list

使用@mnel 的样本数据:

mydf <- data.frame(ID = paste0('ID',1:3), 
 category_list = I(list(c('cat1','cat2','cat3'),  c('cat2','cat3'), c('cat1'))), 
 xval = 1:3, yval = 1:3)

listCol_l从我的“splitstackshape”包中使用

library(splitstackshape)
listCol_l(mydf, "category_list")
#     ID xval yval category_list_ul
# 1: ID1    1    1             cat1
# 2: ID1    1    1             cat2
# 3: ID1    1    1             cat3
# 4: ID2    2    2             cat2
# 5: ID2    2    2             cat3
# 6: ID3    3    3             cat1

unnest从“tidyr”包中使用

library(tidyr)
unnest(mydf, "category_list")
#    ID category_list xval yval
# 1 ID1          cat1    1    1
# 2 ID1          cat2    1    1
# 3 ID1          cat3    1    1
# 4 ID2          cat2    2    2
# 5 ID2          cat3    2    2
# 6 ID3          cat1    3    3

场景 2:列是串联的字符串

使用@BenBolker 的样本数据:

x <- read.table(textConnection('
    ID      category_list    xval    yval
     ID1   "cat1, cat2, cat3"   xnum1   ynum1
     ID2         "cat2, cat3"   xnum2   ynum2
     ID3               "cat1"   xnum3   ynum3'),
                header=TRUE,stringsAsFactors=FALSE)

cSplit从我的“splitstackshape”包中使用

library(splitstackshape)
cSplit(x, "category_list", ",", "long")
#     ID category_list  xval  yval
# 1: ID1          cat1 xnum1 ynum1
# 2: ID1          cat2 xnum1 ynum1
# 3: ID1          cat3 xnum1 ynum1
# 4: ID2          cat2 xnum2 ynum2
# 5: ID2          cat3 xnum2 ynum2
# 6: ID3          cat1 xnum3 ynum3
于 2013-01-09T05:00:54.277 回答