仅使用 reshape(base) 将宽数据重塑为面板并将字符串保留为时间序列标识符

Reshaping wide data to panel using reshape(base) only and keeping strings as time series identifiers

我有一个类似于以下摘录的数据集:

set.seed(1)
df <- data.frame(geography=rep(c(LETTERS),3),December.1999 = runif(n=78),
                 January.2000 = runif(n=78),March.2000 = runif(n=78),
                 April.2000 = runif(n=78), February.2001 = runif(n=78))

我的目的是获得类似于以下格式的长数据集:

geography time           value
A         December.1999  0.26550866 
A         January.2000   0.77732070

目前,我正在使用以下代码:

df_r <- reshape(df, varying = names(df)[2:length(df)], direction = "long",
                v.names = "Value")

产生

    geography time     Value Geography
1.1         A    1 0.2655087         1
2.1         B    1 0.3721239         2
3.1         C    1 0.5728534         3
4.1         D    1 0.9082078         4
5.1         E    1 0.2016819         5
6.1         F    1 0.8983897         6

我想要构建的数据集在 time 列中具有列名:

                    geography    time            Value          
   A.December.199   A            December.1999   0.2655087
   ...              ...          ...            ...

并且会满足以下品质:


我不是在寻找利用 reshape2dplyr 或任何其他附加包的解决方案。我想使用 R Stats 包中可用的 reshape 来实现这个简单的转换。

使用base R方法,我们可以unlist除第一列之外的列来创建'value'列。通过使用data.frame,我们可以根据unlist个元素的长度得到'geography'列进行回收。如果我们需要根据列名创建一个'time'列,我们可以通过数据集的nrow复制列名。在这里,我使用了一个方便的包装器 col,它为要复制的列提供了数字索引。

res <- data.frame(geography=df$geography, time=colnames(df)[-1][col(df[-1])], 
                    value=unlist(df[-1]))
res1 <- res[order(res$geography),]
row.names(res1) <- NULL
head(res1,3)
#  geography          time      value
#1         A December.1999 0.26550866
#2         A December.1999 0.01339033
#3         A December.1999 0.43809711

或者使用reshape(OP代码中的'df_r'),我们可以使用'time'中的数字索引将这些值替换为'df'[的列名=24=]

df_r$time <- colnames(df)[-1][df_r$time]
res2 <-  df_r[order(df_r$geography),-4]
row.names(res2) <- NULL
head(res2,3)
#  geography          time      Value
#1         A December.1999 0.26550866
#2         A December.1999 0.01339033
#3         A December.1999 0.43809711

如果我们需要在 reshape 内执行此操作,我们可以指定 times。默认情况下,它是 times = seq_along(varying[[1]]) (?reshape).

df_r <- reshape(df, varying=names(df)[2:length(df)], times=names(df)[-1], 
            direction='long', v.names='Value')
res3 <- df_r[order(df_r$geography),-4]
row.names(res3) <- NULL
head(res3,3)
#  geography          time      Value
#1         A December.1999 0.26550866
#2         A December.1999 0.01339033
#3         A December.1999 0.43809711