r:将数据转换为另一种格式

时间:2015-08-14 02:01:44

标签: r

在一项实验中,我用两种工具调查了不同任务的工作量。 所以我得到了以下结果:

  Task1ToolA Task1ToolB Task2ToolA Task2ToolB
P1     3          NA         NA          4
P2     NA         4          5           NA
P3     2          NA         NA          3

P1,P2,P3是我的测试人员。我的变量是Task1ToolA,Task1ToolB,Task2ToolA,Task2ToolB。

我认为对于评估和策划,我最好有以下内容:

     EffortTask1 ToolOfTask1 EffortTask2 ToolOfTask2
P1     3              A           4           B
P2     4              B           5           A
P3     2              A           3           B

第一个表中的每个条目在第二个表中产生两个条目,一个用于分数,一个用于工具。那么,我该如何转换呢?我是R和ggplot2的完全初学者。 谢谢你的回答。

3 个答案:

答案 0 :(得分:4)

就我个人而言,我认为您的数据可能会以长格式"而受益。

首先我们重新创建您的数据框:

d <- read.table(text='Task1ToolA Task1ToolB Task2ToolA Task2ToolB
P1     3          NA         NA          4
P2     NA         4          5           NA
P3     2          NA         NA          3', header=TRUE)

现在以长格式创建一个新数据框:

d_new <- data.frame(
  # person: repeat each of the row names as many times as there 
  #         are columns.
  person=rep(row.names(d), ncol(d)),
  # task: extract the task number (see ?sub), from the column names, 
  #       and repeat each as many times as there are rows.
  task=as.numeric(rep(sub('Task(\\d+).*', '\\1', colnames(d)), each=nrow(d))),
  # tool: similarly, extract the tool number from the column names, 
  #       and repeat each as many times as there are rows.
  tool=rep(sub('.*Tool(.*)', '\\1', colnames(d)), each=nrow(d)),
  # score: reduce the data.frame of scores to a vector.
  score=unlist(d)
)

看起来像:

d_new

##             person task tool score
## Task1ToolA1     P1    1    A     3
## Task1ToolA2     P2    1    A    NA
## Task1ToolA3     P3    1    A     2
## Task1ToolB1     P1    1    B    NA
## Task1ToolB2     P2    1    B     4
## Task1ToolB3     P3    1    B    NA
## Task2ToolA1     P1    2    A    NA
## Task2ToolA2     P2    2    A     5
## Task2ToolA3     P3    2    A    NA
## Task2ToolB1     P1    2    B     4
## Task2ToolB2     P2    2    B    NA
## Task2ToolB3     P3    2    B     3 

或者,您可以删除(现在令人困惑的)行名称,并过滤掉NA分数的行:

d_new <- na.omit(d_new)
row.names(d_new) <- NULL
d_new

##   person task tool score
## 1     P1    1    A     3
## 2     P3    1    A     2
## 3     P2    1    B     4
## 4     P2    2    A     5
## 5     P1    2    B     4
## 6     P3    2    B     3

答案 1 :(得分:2)

您可以这样做(数据称为dat

res <- do.call(cbind, lapply(split(as.list(dat), grepl("Task2", colnames(dat))), function(x) {
    inds <- is.na(x[[1]])
    setNames(data.frame(ifelse(inds, x[[2]], x[[1]]), ifelse(inds, "B", "A")),
             c("EffortTask", "ToolOfTask"))
}))
setNames(cbind(rownames(dat), res),
         c("person", paste0(sub("[A-Z]+\\.", "", names(res)), rep(1:2, each=2))))
#   person EffortTask1 ToolOfTask1 EffortTask2 ToolOfTask2
# 1     P1           3           A           4           B
# 2     P2           4           B           5           A
# 3     P3           2           A           3           B

并且(更简单!),使用tidyrdplyr

将其设置为长格式
library(dplyr)
library(tidyr)
library(reshape2)

dat %>% mutate(id=rownames(dat)) %>%
  melt %>% separate(variable, c("task", "tool"), "Tool") %>%
  .[complete.cases(.),]
#    id  task tool value
# 1  P1 Task1    A     3
# 3  P3 Task1    A     2
# 5  P2 Task1    B     4
# 8  P2 Task2    A     5
# 10 P1 Task2    B     4
# 12 P3 Task2    B     3

答案 2 :(得分:0)

我们可以使用grepmax.col来获取输出。

d1 <- data.frame(
        lapply(c('Task1', 'Task2'), function(x) {
          x1 <- df1[grep(x, names(df1))]
          i1 <- max.col(!is.na(x1))
          setNames(data.frame(x1[cbind(1:nrow(x1), i1)], LETTERS[i1]), 
                   paste0(c('Effort', 'ToolOf'), x))
       }))
row.names(d1) <- row.names(df1)
d1
#   EffortTask1 ToolOfTask1 EffortTask2 ToolOfTask2
#P1           3           A           4           B
#P2           4           B           5           A
#P3           2           A           3           B

上述代码涉及的步骤如下。我们使用lapply

遍历字符串(&#39; Task1&#39;,&#39; Task2&#39;)
   lapply(c('Task1', 'Task2'), function(x) {...

然后,我们将&#39; df1&#39;的列进行子集化。使用grep

     ...
     x1 <- df1[grep(x, names(df1))]
     ...

根据&#39; x1&#39;的非NA值创建列索引(&#39; i1&#39;)与max.col。这基本上给出了每行的最大值的列索引。 !is.na(x1)返回TRUE/FALSEnon-NA/NA的逻辑矩阵。因此,如果{1}}用于第1列的第1行,则返回2,同样,这是针对每一行完成的。

TRUE

在下一步中,我们可以使用&#39; i1&#39;创建... i1 <- max.col(!is.na(x1)) ... 。指数。我们data.frame使用行索引(cbind)来创建行/列索引,这可用于从&#39; x1&#39;中提取元素。创造'努力'&#39;柱。 &#39; ToolOf&#39;列是使用&#39; i1&#39;创建的。作为1:nrow(x1)的索引。

LETTERS

我们更改了&#39;列表&#39; &#39; data.frames&#39;使用... setNames(data.frame(x1[cbind(1:nrow(x1), i1)], LETTERS[i1]), paste0(c('Effort', 'ToolOf'), x)) ... 调用将单个data.frame更改为原始数据集的data.frame

数据

row.names