Измените форму таблицы в длинном формате, чтобы разделить столбцы

У меня есть таблица, которая выглядит так:

|Condition|Session|Time|
|        A|      1| 100|
|        A|      1| 200|
|        B|      2| 200|
|        B|      2| 300|
|        B|      2| 500|
|        A|      3| 300|
|        A|      4| 200|

Я хочу преобразовать его в следующий формат:

|   A|   B|   A|   A|
|   1|   2|   3|   4|
| 100| 200| 300| 200|
| 200| 300|    |    |
|    | 500|    |    |

Это означает, что первые две строки - это «Условие» и «Сеанс», а остальные строки представляют столбец «Время» (переменное количество строк).

Как я могу добиться этого в R?


r
person kshahar    schedule 19.11.2012    source источник
comment
Я думаю, что в качестве общей стратегии я бы начал с попытки изменить исходный df на широкий, где имена столбцов - Condiion.Session, например А.1, В.2. А.3, А.4. Я бы просто скрыл имена столбцов в df с 2 строками и привязал df к этому.   -  person frankc    schedule 19.11.2012
comment
Читатели могут заметить, как каждый отвечающий включает код для преобразования образца таблицы в код, читаемый R, через read.table или data.frame. Использование dput() как в dput(mytable) и включение результата в вопрос было бы вежливым способом сохранить их на этом шаге. :-)   -  person MattBagg    schedule 20.11.2012
comment
@MattBagg, ты прав, это было не очень вежливо   -  person kshahar    schedule 23.11.2012
comment
@kshahar, оглядываясь назад, я тоже не был. Прости за это.   -  person MattBagg    schedule 23.11.2012


Ответы (3)


Предлагаю другое возможное решение с использованием ddply из пакета plyr и dcast из reshape2:

library(reshape2)
library(plyr)

dat = read.table(text=gsub("\\|", " ", "|Condition|Session|Time|
|        A|      1| 100|
|        A|      1| 200|
|        B|      2| 200|
|        B|      2| 300|
|        B|      2| 500|
|        A|      3| 300|
|        A|      4| 200|"), header=TRUE)

# Add column 'Rank' for each combination of Condition by Session.
dat = ddply(dat, .(Condition, Session), .fun=summarise, 
            Rank=rank(Time), Time=Time)

res = dcast(dat, Condition + Session ~ Rank, value.var="Time")

# Sort by 'Session'.
res = res[order(res$Session), ]

# As @Ali pointed out, you may want to leave the results as
# an un-transposed data.frame.
res

#   Condition Session   1   2   3
# 1         A       1 100 200  NA
# 4         B       2 200 300 500
# 2         A       3 300  NA  NA
# 3         A       4 200  NA  NA

# Transposing will coerce the data.frame to a character matrix.
t(res)

#           1     4     2     3    
# Condition "A"   "B"   "A"   "A"  
# Session   "1"   "2"   "3"   "4"  
# 1         "100" "200" "300" "200"
# 2         "200" "300" NA    NA   
# 3         NA    "500" NA    NA   
person bdemarest    schedule 19.11.2012

Вот один вариант. Предупреждение (потенциально большое) заключается в том, что я использую (очень полезную), но нестандартную пользовательскую функцию с именем cbind.fill:

> dat <- read.table(text = "|Condition|Session|Time|
+ |        A|      1| 100|
+ |        A|      1| 200|
+ |        B|      2| 200|
+ |        B|      2| 300|
+ |        B|      2| 500|
+ |        A|      3| 300|
+ |        A|      4| 200|",header = TRUE,sep = "|")
dat$X <- dat$X.1 <- NULL

dat$Condition <- factor(dat$Condition,labels = LETTERS[1:2])

tmp <- with(dat,split(Time,list(Condition,Session)))
tmp <- tmp[sapply(tmp,function(x) length(x) > 0)]
res <- do.call(cbind.fill,tmp)

nm <- strsplit(names(tmp),split="\\.")

res <- rbind(as.numeric(sapply(nm,'[',2)),res)
colnames(res) <- sapply(nm,'[',1)
> res
       A   B   A   A
[1,]   1   2   3   4
[2,] 100 200 300 200
[3,] 200 300  NA  NA
[4,]  NA 500  NA  NA

Основную идею cbind.fill можно найти в этом вопросе. Однако я не буду обещать идентичных результатов, поскольку я использую там сильно измененную версию кода.

person joran    schedule 19.11.2012

Прежде всего, каждый столбец data.frame имеет один и тот же тип. Таким образом, у вас может быть желаемый стол в транспонированной форме.

Возможно, вы сможете сделать следующее:

foo = data.frame(Condition=c("A","A","B","B","B","A","A"), 
                 Session=c(1,1,2,2,2,3,4), 
                 Time = c(1,2,2,3,5,3,2)*100)
bar = aggregate(Time~Condition+Session, foo, identity)
bar
#   Condition Session          Time
# 1         A       1      100, 200
# 2         B       2 200, 300, 500
# 3         A       3           300
# 4         A       4           200
bar[1,3]
# $`0`
# [1] 100 200
person Ali    schedule 19.11.2012