首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >扩展R中的csv数据

扩展R中的csv数据
EN

Stack Overflow用户
提问于 2015-01-03 09:49:35
回答 2查看 106关注 0票数 0

我有以下列标题的数据:

代码语言:javascript
复制
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

我想将其转换为具有以下列标题的格式:

代码语言:javascript
复制
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中实现这一点呢?我一直在尝试使用“重塑”包。谢谢!

EN

回答 2

Stack Overflow用户

发布于 2015-01-03 10:48:25

(我利用这个机会了解了一点tidyr,我很高兴我这样做了。)

正如@JamesKing建议的那样,你提供的不是最好的MWE,所以我创建了一些类似结构的数据。不过,我认为这一切都适用于您的示例,因此通过一些解释,您应该能够将其转换为您的数据。话虽如此,由于您似乎是从Excel电子表格开始的,因此提出一种简化数据的gatherseparate的命名约定将是有益的。

我的数据:

代码语言:javascript
复制
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

数据类型:

  • 静态列:sheetNumyearroleInDebate。此数据不会在其他任何地方使用,并将被复制到每个人的每一行。任何内容都不是基于这些列的gathered、separated或spread
  • 其余列是数据嵌入在列名中的列。我的意思是,Clarity.1中存储了数据1,需要巧妙地将其分离出来。虽然我每个人只有两个专栏,但这很容易转化为更多。

底线,正面向上

(如果您不熟悉dplyrmagrittr中的%>%中缀运算符,我鼓励您在其他地方研究它。它对于理解这个建议的解决方案是方便和关键的。)

现在来看解决方案,非常简单:

代码语言:javascript
复制
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步骤简单地将未提及的列组合成一对键/值的列,如下所示:

代码语言:javascript
复制
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列:

代码语言:javascript
复制
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

这里发生的事情不多,但这对下一步非常重要:扩大数据,或者从不同的列的键/值对(现在使用skillval)中对数据进行spread,这将创建名为ClarityEffort的新列,正如我们在上面的解决方案中看到的那样。

希望这能有所帮助。

顺便说一句:对于一个好的MWE,通常建议提供来自dput(dat)的输出,其中dat是一个,但具有代表性的数据结构,可以帮助我们理解起点和您的目标输出。在这里,为两者创建一个较小的data.frame将是合适的。

票数 5
EN

Stack Overflow用户

发布于 2015-01-03 13:10:21

假设@r2evans的样本数据在某种程度上代表了您的问题,这里有几个需要考虑的其他选项。

选项1:Base R的reshape

奇怪的是,以您描述的任务命名的函数--reshape()--在重塑工具时似乎是“害群之马”。如果它是您的常规工具包的一部分,那么要掌握它的诀窍并不太难。

对于此问题,一种方法可能是:

代码语言:javascript
复制
reshape(dat, direction = "long", idvar = 1:3, varying = 4:ncol(dat), sep = ".")

我对reshape()的担忧不是它的语法,而是(1)它不能处理不平衡的宽到长的转换(例如,如果你有3列“清晰”列,但只有2列“努力”列),(2)当你开始处理很多行或很多要重塑的列时,它可能会非常慢。因此,我编写了merged.stack

选项2merged.stack

我把merged.stack作为我的"splitstackshape“包的一部分,来处理与reshape(., direction = "long", ...)类似的重塑任务(例如,这不同于"reshape"/"reshape2”中的melt (以及随后的“reshape2”中的gather ))。我还想通过识别变量“存根”(在本例中是“清晰度”和“努力”)来简化选择感兴趣的变量的过程。

正如前面提到的,merged.stack也被设计为快速的。

代码语言:javascript
复制
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,因为最好等产品发布。

以下是一些示例数据:

代码语言:javascript
复制
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 = "."))))

下面是两个经过测试的函数:

代码语言:javascript
复制
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次运行的结果:

代码语言:javascript
复制
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

并验证输出是否相同:

代码语言:javascript
复制
out1 <- r2evans()
out2 <- ananda()

library(compare)
compare(out1, out2, allowAll = TRUE)
# TRUE
#   renamed
#   dropped names
#   dropped attributes
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27750945

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档