在R中,将数据框的对角线转换为行

6

我正在开发一个模型,用于预测某一年龄段的生育率。目前我有一个类似这样的数据框,其中行是年龄,列是年份。每个单元格里的数值是该年份对应年龄的生育率:

> df1
   iso3    sex age fert1953 fert1954 fert1955
14  AUS female  13    0.000  0.00000  0.00000
15  AUS female  14    0.000  0.00000  0.00000
16  AUS female  15   13.108 13.42733 13.74667
17  AUS female  16   26.216 26.85467 27.49333
18  AUS female  17   39.324 40.28200 41.24000

然而,我希望每一行都是一个群体。因为行和列代表的是各个年份,所以可以通过获取对角线来获得群体数据。我想要的结果如下:

> df2
   iso3    sex ageIn1953 fert1953  fert1954  fert1955
14  AUS female        13    0.000   0.00000  13.74667
15  AUS female        14    0.000  13.42733  27.49333
16  AUS female        15   13.108  26.85467  41.24000
17  AUS female        16   26.216  40.28200  [data..] 
18  AUS female        17   39.324  [data..]  [data..] 

这里是 df1 数据框:

df1 <- structure(list(iso3 = c("AUS", "AUS", "AUS", "AUS", "AUS"), sex = c("female", 
"female", "female", "female", "female"), age = c(13, 14, 15, 
16, 17), fert1953 = c(0, 0, 13.108, 26.216, 39.324), fert1954 = c(0, 
0, 13.4273333333333, 26.8546666666667, 40.282), fert1955 = c(0, 
0, 13.7466666666667, 27.4933333333333, 41.24)), .Names = c("iso3", 
"sex", "age", "fert1953", "fert1954", "fert1955"), class = "data.frame", row.names = 14:18)

编辑:

这是我最终使用的解决方法。它基于David的答案,但我需要为每个iso3级别执行此操作。

df.ls <- lapply(split(f3, f = f3$iso3), FUN = function(df1) {
  n <- ncol(df1) - 4
  temp <- mapply(function(x, y) lead(x, n = y), df1[, -seq_len(4)], seq_len(n))
  return(cbind(df1[seq_len(4)], temp))
})
f4 <- do.call("rbind", df.ls)

你只是想拖延你的数据集吗? - David Arenburg
是的,但我认为那会非常繁琐。我要在50年内为188个国家做这件事。如果你能想到一个好的方法来解决这个问题,那就太好了。 - rsoren
2个回答

4

我没有测试过速度,但是 data.tablev1.9.5 最近实现了一个新的(用 C 写的)lead/lag 函数,叫做 shift

因此,对于您想要移动的列,您可以潜在地与 mapply 结合使用,例如

library(data.table)
n <- ncol(df1) - 4 # the number of years - 1
temp <- mapply(function(x, y) shift(x, n = y, type = "lead"), df1[, -seq_len(4)], seq_len(n))
cbind(df1[seq_len(4)], temp) # combining back with the unchanged columns
#    iso3    sex age fert1953 fert1954 fert1955
# 14  AUS female  13    0.000  0.00000 13.74667
# 15  AUS female  14    0.000 13.42733 27.49333
# 16  AUS female  15   13.108 26.85467 41.24000
# 17  AUS female  16   26.216 40.28200       NA
# 18  AUS female  17   39.324       NA       NA

编辑:您可以轻松地从GitHub安装data.table的开发版本,方法如下:

library(devtools) 
install_github("Rdatatable/data.table", build_vignettes = FALSE)

无论如何,如果你想使用dplyr,请看这里。
library(dplyr)
n <- ncol(df1) - 4 # the number of years - 1
temp <- mapply(function(x, y) lead(x, n = y), df1[, -seq_len(4)], seq_len(n))
cbind(df1[seq_len(4)], temp)
#    iso3    sex age fert1953 fert1954 fert1955
# 14  AUS female  13    0.000  0.00000 13.74667
# 15  AUS female  14    0.000 13.42733 27.49333
# 16  AUS female  15   13.108 26.85467 41.24000
# 17  AUS female  16   26.216 40.28200       NA
# 18  AUS female  17   39.324       NA       NA

这看起来很不错。不幸的是,v1.9.4是CRAN上data.table的最新版本,我在从GitHub下载dev版本时遇到了麻烦。显然,在Windows上这是一个常见的问题。我正在尝试使用dplyr的lead()函数代替;我认为它应该可以工作... - rsoren
我进行了调整,以考虑到需要针对 iso3 的每个值单独完成此操作(请参见我的上面的编辑)。使用 data.table 的问题在于我遇到了“命令失败(1)”错误,这比通常的 install_github() 更困难。data.table 的安装页面有关于此的链接。非常感谢! - rsoren

1
这是一个基于R语言的方法:
df1[,5:ncol(df1)] <- mapply(function(x, y) {vec.list <- df1[-1:-y, x]
                       length(vec.list) <- nrow(df1)
                       vec.list},
                       x=5:ncol(df1), y=1:(ncol(df1)-4))
df1
#   iso3    sex age fert1953 fert1954 fert1955
#14  AUS female  13    0.000  0.00000 13.74667
#15  AUS female  14    0.000 13.42733 27.49333
#16  AUS female  15   13.108 26.85467 41.24000
#17  AUS female  16   26.216 40.28200       NA
#18  AUS female  17   39.324       NA       NA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接