对第1列进行因子分解,并根据第1列的分解水平转置其他列的相应行

Factor column 1 and transpose the corresponding rows of other columns according to factored levels of column 1

我有一个大型数据框,直接从 SQL 数据库导入,具有以下结构类型(用于可重现的示例):

我想分解前 3 列,“id”、“day”和“type”。这 3 列始终相互依赖并相应地分解。 对于因式分解的列,我想将“valueTitle”列转置为新列标题的行,并将“value”列转置为正确“valueTitle”下的行。它应该看起来像这样:

可重现的例子:

id <- c(5,5,5,6,6,6,7,7,7) 
day <- c("01.01.2000", "01.01.2000", "01.01.2000", "01.01.2001", "01.01.2001", "01.01.2001", "01.01.2002", "01.01.2002", "01.01.2002") 
type <- c("green", "green", "green","orange","orange","orange", "blue", "blue", "blue")
valueTitle <- c("title1","title2","title3","title1","title2","title3","title1","title2","title3")
value <- c(0.2, 0.6, 0.9, 0.6, 0.9, 0.9, 2, 1, 7)
df <- data.frame(id, day, type, valueTitle, value) 
df$id<-as.factor(df$id)      
df

  id        day   type valueTitle value
1  5 01.01.2000  green     title1   0.2
2  5 01.01.2000  green     title2   0.6
3  5 01.01.2000  green     title3   0.9
4  6 01.01.2001 orange     title1   0.6
5  6 01.01.2001 orange     title2   0.9
6  6 01.01.2001 orange     title3   0.9
7  7 01.01.2002   blue     title1   2.0
8  7 01.01.2002   blue     title2   1.0
9  7 01.01.2002   blue     title3   7.0

我一直在寻找一种只使用矢量化操作的解决方案,但想了很久也找不到好的方法。我只提出了以下解决方案,但基于一个循环,这似乎是错误的,原因有很多:

m<-matrix(ncol=3,nrow=3); m<-as.data.frame(m);m # pretend I know the real size, in reality this is not fixed
for ( i in  min(levels(df$id)):max(levels(df$id))){ 
  m[(df$id==i), ]<-(df[ ,('value')])
}
m<-t(m)
df2<-data.frame(m)
colnames(df2)<-(levels(df$valueTitle))
df2 <- cbind(id=levels(df$id), df2[,1:ncol(df2)])
df2

   id        day   type title1 title2 title3
V1  5 01.01.2000   blue    0.2    0.6    0.9
V2  6 01.01.2001  green    0.6    0.9    0.9
V3  7 01.01.2002 orange    2.0    1.0    7.0

这是错误的,因为 'type' 被混淆了,无论哪种方式,这种方法都会导致许多潜在的错误。我的真实数据集很大,'valueTitle' 的数量可能因 'id' 而异。

您能否建议任何可以更有效地对此类数据执行因子和转置操作的方法?

(如果SQL有直接实现的方法就好了!)

我们可以使用dcast

library(reshape2)
dcast(df, id+day+type~valueTitle, value.var='value')

spreadtidyr 将格式从 'long' 重塑为 'wide'。

library(tidyr)
spread(df, valueTitle, value)

使用PIVOT

CREATE TABLE #tab (
   id         INTEGER  NOT NULL
  ,[day]       DATE  NOT NULL
  ,type       VARCHAR(100)  NOT NULL
  ,valueTitle VARCHAR(60) NOT NULL
  ,value      NUMERIC(10,2) NOT NULL);

INSERT INTO #tab (id,[day],type,valueTitle,value) 
VALUES (5,'2000-01-01','green','title1',0.2), (5,'2000-01-01','green','title2',0.6),
(5,'2000-01-01','green','title3',0.9), (6,'2001-01-01','orange','title1',0.6),
(6,'2001-01-01','orange','title2',0.9),(6,'2001-01-01','orange','title3',0.9),
(7,'2002-01-01','blue','title1',2.0), (7,'2002-01-01','blue','title2',1.0),
(7,'2002-01-01','blue','title3',7.0);

SELECT id, [day], type,title1, title2, title3
FROM #tab
PIVOT (MAX(value)
       FOR valueTitle IN (title1, title2, title3)) p;

LiveDemo