我有以下列标题的数据:
Sheet Number, Year, Term, Class, Debate #, Role in Debate, Gender of Evaluator, Person #1 Clarity, Person #1 Effort, Person #1 Gender, Person #1 Origin, Debater Number, Person #2 Clarity, Person #2 Effort, Person #2 Gender, Person #2 Origin, Debater Number, Person #3 Clarity, Person #3 Effort, Person #3 Gender, Person #3 Origin, Debater Number, Person #4 Clarity, Person #4 Effort, Person #4 Gender, Person #4 Origin, Debater Number, Person #5 Clarity, Person #5 Effort, Person #5 Gender, Person #5 Origin, Debater Number, Person #6 Clarity, Person #6 Effort, Person #6 Gender, Person #6 Origin, Debater Number, Person #7 Clarity, Person #7 Effort, Person #7 Gender, Person #7 Origin, Debater Number, Person #8 Clarity, Person #8 Effort, Person #8 Gender, Person #8 Origin, Debater Number, Learned from Team 1, Learned from Team 2, Who won?, Sheet all 10s?, Evaluator Class Year我想将其转换为具有以下列标题的格式:
Sheet Number, Year, Term, Class, Debate #, Gender of Evaluator, Evaluator Class Year, Role in Debate, Debate Team Member #, Debater Number, Gender of Debate Team Member, Origin of Debate Team Member, Clarity of Debate Team Member, Effort of Debate Team Member, Learned from Team 1, Learned from Team 2, Who won?, Sheet all 10s?, =1 if Gender of Evaluator==Gender of Debater两者之间的主要区别是,在第一种格式中,每个页码都有5-8个与之相关联的“人员”编号。第二种格式,每个页码都有一个与之关联的人(因此每个页码出现多次,数据被“展开”)。
我如何在R中实现这一点呢?我一直在尝试使用“重塑”包。谢谢!
发布于 2015-01-03 10:48:25
(我利用这个机会了解了一点tidyr,我很高兴我这样做了。)
正如@JamesKing建议的那样,你提供的不是最好的MWE,所以我创建了一些类似结构的数据。不过,我认为这一切都适用于您的示例,因此通过一些解释,您应该能够将其转换为您的数据。话虽如此,由于您似乎是从Excel电子表格开始的,因此提出一种简化数据的gather和separate的命名约定将是有益的。
我的数据:
set.seed(1)
n <- 5
dat <- data.frame(
sheetNum = 1:n,
year = sample(2000:2025, size = n),
roleInDebate = sample(letters, size = n, replace = TRUE),
Clarity.1 = sample(10, size = n, replace = TRUE),
Effort.1 = sample(10, size = n, replace = TRUE),
Clarity.2 = sample(10, size = n, replace = TRUE),
Effort.2 = sample(10, size = n, replace = TRUE),
Clarity.3 = sample(10, size = n, replace = TRUE),
Effort.3 = sample(10, size = n, replace = TRUE))
dat
# sheetNum year roleInDebate Clarity.1 Effort.1 Clarity.2 Effort.2 Clarity.3
# 1 1 2006 x 3 5 10 4 5
# 2 2 2009 y 2 8 3 1 6
# 3 3 2013 r 7 10 7 4 5
# 4 4 2020 q 4 4 2 9 2
# 5 5 2004 b 8 8 3 4 9数据类型:
sheetNum、year、roleInDebate。此数据不会在其他任何地方使用,并将被复制到每个人的每一行。任何内容都不是基于这些列的gathered、separated或spread。Clarity.1中存储了数据1,需要巧妙地将其分离出来。虽然我每个人只有两个专栏,但这很容易转化为更多。底线,正面向上
(如果您不熟悉dplyr和magrittr中的%>%中缀运算符,我鼓励您在其他地方研究它。它对于理解这个建议的解决方案是方便和关键的。)
现在来看解决方案,非常简单:
library(tidyr)
library(dplyr)
dat %>%
gather(var, val, -sheetNum, -year, -roleInDebate) %>%
separate(var, c('skill', 'person'), '\\.') %>%
spread(skill, val)
# sheetNum year roleInDebate person Clarity Effort
# 1 1 2006 x 1 3 5
# 2 1 2006 x 2 10 4
# 3 1 2006 x 3 5 7
# 4 2 2009 y 1 2 8
# 5 2 2009 y 2 3 1
# 6 2 2009 y 3 6 8
# 7 3 2013 r 1 7 10
# 8 3 2013 r 2 7 4
# 9 3 2013 r 3 5 2
# 10 4 2020 q 1 4 4
# 11 4 2020 q 2 2 9
# 12 4 2020 q 3 2 8
# 13 5 2004 b 1 8 8
# 14 5 2004 b 2 3 4
# 15 5 2004 b 3 9 5拆分一下
为了了解发生了什么,让我们逐步了解一下。gather步骤简单地将未提及的列组合成一对键/值的列,如下所示:
dat %>% gather(var, val, -sheetNum, -year, -roleInDebate) %>% head()
# sheetNum year roleInDebate var val
# 1 1 2006 x Clarity.1 3
# 2 2 2009 y Clarity.1 2
# 3 3 2013 r Clarity.1 7
# 4 4 2020 q Clarity.1 4
# 5 5 2004 b Clarity.1 8
# 6 1 2006 x Effort.1 5请注意,我所包含的带有-前缀的列是如何逐字保持的。接下来,我们需要拆分(或separate) var列:
dat %>%
gather(var, val, -sheetNum, -year, -roleInDebate) %>%
separate(var, c('skill', 'person'), '\\.') %>% head()
# sheetNum year roleInDebate skill person val
# 1 1 2006 x Clarity 1 3
# 2 2 2009 y Clarity 1 2
# 3 3 2013 r Clarity 1 7
# 4 4 2020 q Clarity 1 4
# 5 5 2004 b Clarity 1 8
# 6 1 2006 x Effort 1 5这里发生的事情不多,但这对下一步非常重要:扩大数据,或者从不同的列的键/值对(现在使用skill和val)中对数据进行spread,这将创建名为Clarity和Effort的新列,正如我们在上面的解决方案中看到的那样。
希望这能有所帮助。
顺便说一句:对于一个好的MWE,通常建议提供来自dput(dat)的输出,其中dat是一个小,但具有代表性的数据结构,可以帮助我们理解起点和您的目标输出。在这里,为两者创建一个较小的data.frame将是合适的。
发布于 2015-01-03 13:10:21
假设@r2evans的样本数据在某种程度上代表了您的问题,这里有几个需要考虑的其他选项。
选项1:Base R的reshape
奇怪的是,以您描述的任务命名的函数--reshape()--在重塑工具时似乎是“害群之马”。如果它是您的常规工具包的一部分,那么要掌握它的诀窍并不太难。
对于此问题,一种方法可能是:
reshape(dat, direction = "long", idvar = 1:3, varying = 4:ncol(dat), sep = ".")我对reshape()的担忧不是它的语法,而是(1)它不能处理不平衡的宽到长的转换(例如,如果你有3列“清晰”列,但只有2列“努力”列),(2)当你开始处理很多行或很多要重塑的列时,它可能会非常慢。因此,我编写了merged.stack。
选项2:merged.stack
我把merged.stack作为我的"splitstackshape“包的一部分,来处理与reshape(., direction = "long", ...)类似的重塑任务(例如,这不同于"reshape"/"reshape2”中的melt (以及随后的“reshape2”中的gather ))。我还想通过识别变量“存根”(在本例中是“清晰度”和“努力”)来简化选择感兴趣的变量的过程。
正如前面提到的,merged.stack也被设计为快速的。
library(splitstackshape)
merged.stack(dat, var.stubs = c("Clarity", "Effort"), sep = ".")
# sheetNum year roleInDebate .time_1 Clarity Effort
# 1: 1 2006 x 1 3 5
# 2: 1 2006 x 2 10 4
# 3: 1 2006 x 3 5 7
# 4: 2 2009 y 1 2 8
# 5: 2 2009 y 2 3 1
# 6: 2 2009 y 3 6 8
# 7: 3 2013 r 1 7 10
# 8: 3 2013 r 2 7 4
# 9: 3 2013 r 3 5 2
# 10: 4 2020 q 1 4 4
# 11: 4 2020 q 2 2 9
# 12: 4 2020 q 3 2 8
# 13: 5 2004 b 1 8 8
# 14: 5 2004 b 2 3 4
# 15: 5 2004 b 3 9 5选项3:等待来自"data.table“版本1.9.8的melt
好的。好吧,这可能不是一个真正的选择(但是"data.table“开发人员工作得很快,所以谁知道呢)但是在"data.table”的1.9.8版本中,您将能够melt指定的列列表。See this issue for more details。或者,如果您更喜欢冒险,请安装the 1.9.8 branch并立即试用:-)
最终,这可能会使merged.stack变得多余,因为它将具有类似的功能,但速度更快(从我在几个试验中看到的情况来看)。
更新--基准测试
下面我只测试了merged.stack和@r2evan的方法。我没有测试reshape(),因为我害怕它会减慢我的系统速度。我没有测试"data.table“中的melt,因为最好等产品发布。
以下是一些示例数据:
set.seed(1)
n <- 100000
r <- 6
dat <- data.frame(
sheetNum = 1:n,
year = sample(2000:2025, size = n, TRUE),
roleInDebate = sample(letters, size = n, replace = TRUE),
matrix(sample(10, n * r * 2, TRUE), nrow = n,
dimnames = list(NULL, paste(c("Clarity", "Effort"),
rep(seq_len(r), each = 2),
sep = "."))))下面是两个经过测试的函数:
r2evans <- function() {
dat %>%
gather(var, val, -sheetNum, -year, -roleInDebate) %>%
separate(var, c('skill', 'person'), '\\.') %>%
spread(skill, val)
}
ananda <- function() {
merged.stack(dat, var.stubs = c("Clarity", "Effort"), sep = ".")
}以下是10次运行的结果:
library(microbenchmark)
microbenchmark(r2evans(), ananda(), times = 10)
# Unit: milliseconds
# expr min lq mean median uq max neval
# r2evans() 3514.0961 3603.7102 3839.6097 3713.6705 3959.5320 4380.4601 10
# ananda() 320.5602 336.2396 363.7165 367.3344 386.3064 417.7994 10并验证输出是否相同:
out1 <- r2evans()
out2 <- ananda()
library(compare)
compare(out1, out2, allowAll = TRUE)
# TRUE
# renamed
# dropped names
# dropped attributeshttps://stackoverflow.com/questions/27750945
复制相似问题