1

我有一个看起来像这样的数据框:

ID rd_test_2011 rd_score_2011 mt_test_2011 mt_score_2011 rd_test_2012 rd_score_2012 mt_test_2012 mt_score_2012
1  A            80            XX           100           NA           NA            BB           45 
2  XX           90            NA           NA            AA           80            XX           80

我想编写一个脚本,对于在 yy_test_20xx 列中没有 NA 的 ID,创建一个新的数据框,其中主题取自列标题、测试名称、测试分数和年份取自列标题. 因此,在此示例中,ID 1 将具有三个条目。预期输出如下所示:

ID   Subject    Test        Score        Year
1    rd         A           80           2011
1    mt         XX          100          2012
1    mt         BB          45           2012
2    rd         XX          90           2011
2    rd         AA          80           2012
2    mt         XX          80           2012

我已经尝试了 reshape 和各种形式的 merge.stack ,从某种意义上说,我得到了一个正确的输出,但我无法很好地理解输入以一直到达那里:

library(splitstackshape)
merged.stack(x, id.vars='id', var.stubs=c("rd_test","mt_test"), sep="_")

我在重塑方面取得了更大的成功(越来越接近):

y<- reshape(x, idvar="id", ids=1:nrow(x), times=grep("test", names(x), value=TRUE), 
      timevar="year", varying=list(grep("test", names(x), value=TRUE), grep("score",
      names(x), value=TRUE)), direction="long", v.names=c("test", "score"),
      new.row.names=NULL) 
4

3 回答 3

2

使用reshape

 dat.long <- reshape(dat, direction="long",  varying=list(c(2, 4,6), c(3, 5,7)), 
                       times=2011:2013,timevar='Year',
                       sep="_", v.names=c("Test", "Score"))


dat.long[complete.cases(dat.long),]

      ID Year Test Score id
1.2011  1 2011    A    80  1
2.2011  2 2011   XX    90  2
4.2011  4 2011    A    50  4
5.2011  5 2011    C    50  5
1.2012  1 2012   XX   100  1
3.2012  3 2012    A    10  3
4.2012  4 2012   XX    60  4
5.2012  5 2012    A    75  5
2.2013  2 2013   AA    80  2
4.2013  4 2013   AA    99  4
于 2013-10-17T22:58:37.880 回答
2

这将使您的数据转换为正确的格式:

df.long = reshape(df, idvar="ID", ids=1:nrow(df), times=grep("Test", names(df), value=TRUE),
 timevar="Year", varying=list(grep("Test", names(df), value=TRUE), 
grep("Score", names(df), value=TRUE)), direction="long", v.names=c("Test", "Score"),
new.row.names=NULL) 

然后省略NA

df.long = df.long[!is.na(df.long$Test),]

然后拆分Year删除Test_

df.long$Year = sapply(strsplit(df.long$Year, "_"), `[`, 2)

并通过以下方式订购ID

df.long[order(df.long$ID),]

   ID Year Test Score
1   1 2011    A    80
5   1 2012   XX   100
2   2 2011   XX    90
9   2 2013   AA    80
6   3 2012    A    10
3   4 2011    A    50
7   4 2012   XX    60
10  4 2013   AA    99
4   5 2011    C    50
8   5 2012    A    75
于 2013-10-17T22:58:50.393 回答
1

考虑到您的更新,我已经完全重写了这个答案。如果您想查看旧版本,请查看历史记录。

主要问题是您的数据在某种程度上是“双宽”。因此,您实际上可以通过在“长”方向上进行两次整形来解决您的问题。或者,使用meltand*cast以非常长的格式融合您的数据并将其转换为半宽格式。

但是,我仍然建议“splitstackshape”(不仅仅是因为我写了它)。它可以很好地处理这个问题,但它需要你重新排列你names的数据。将导致新列名称的名称部分应该放在第一位。在您的示例中,这意味着“测试”和“分数”应该是变量名的第一部分。

为此,我们可以使用 somegsub重新排列现有名称。

library(splitstackshape)
setnames(mydf, gsub("(rd|mt)_(score|test)_(.*)", "\\2_\\1_\\3", names(mydf)))
names(mydf)
# [1] "ID"            "test_rd_2011"  "score_rd_2011" "test_mt_2011" 
# [5] "score_mt_2011" "test_rd_2012"  "score_rd_2012" "test_mt_2012" 
# [9] "score_mt_2012"
out <- merged.stack(mydf, "ID", var.stubs=c("test", "score"), sep="_")
setnames(out, c(".time_1", ".time_2"), c("Subject", "Year"))
out[complete.cases(out), ]
#    ID Subject Year test score
# 1:  1      mt 2011   XX   100
# 2:  1      mt 2012   BB    45
# 3:  1      rd 2011    A    80
# 4:  2      mt 2012   XX    80
# 5:  2      rd 2011   XX    90
# 6:  2      rd 2012   AA    80

为了他人的利益,此答案中的“mydf”定义为:

mydf <- structure(list(ID = 1:2, rd_test_2011 = c("A", "XX"), 
    rd_score_2011 = c(80L, 90L), mt_test_2011 = c("XX", NA), 
    mt_score_2011 = c(100L, NA), rd_test_2012 = c(NA, "AA"), 
    rd_score_2012 = c(NA, 80L), mt_test_2012 = c("BB", "XX"), 
    mt_score_2012 = c(45L, 80L)), 
    .Names = c("ID", "rd_test_2011", "rd_score_2011", "mt_test_2011", 
    "mt_score_2011", "rd_test_2012", "rd_score_2012", "mt_test_2012", 
    "mt_score_2012"), class = "data.frame", row.names = c(NA, -2L))
于 2013-10-18T04:26:11.053 回答