我有一个数据框,其距离在第一个列中,而类别在第二个列中:
data.tab <- read.table(text = "
644 1
76 1
78 1
350 1
45 1
37 2
366 2
46 2
71 3
28 3
97 3
30 3
55 3
65 3
116 3
30 3
18 4
143 4
99 4")
我想通过根据最长的类将零添加到新的数据框中。结果将是:
data.tab <- read.table(text = "
1 644 76 78 350 45 0 0 0
2 37 366 46 0 0 0 0 0
3 71 28 97 30 55 65 116 30
4 18 143 99 0 0 0 0 0")
答案 0 :(得分:4)
这基本上可以归结为简单的从长到宽的重塑
randomList = []
答案 1 :(得分:2)
1)xtabs 仅使用基数R在类中创建一个序列号列,然后使用xtabs
将其重新排列为表格。最后将其转换为数据帧。如果一个表足够,则省略最后一行代码。
data.tab2 <- transform(data.tab, seq = ave(V2, V2, FUN = seq_along))
xt <- xtabs(V1 ~ V2 + seq, data.tab2)
as.data.frame.matrix(xt)
给予:
1 2 3 4 5 6 7 8
1 644 76 78 350 45 0 0 0
2 37 366 46 0 0 0 0 0
3 71 28 97 30 55 65 116 30
4 18 143 99 0 0 0 0 0
2)ts 另一个基本的R解决方案是将每个类的元素转换为ts
系列,从而给tt
一个多变量时间序列,在其末尾具有NA较短的。在第二行代码中将这些NA转换为0,然后在最后一行中将其转换为数据帧。
tt <- do.call("cbind", lapply(unstack(data.tab), ts))
tt[] <- ifelse(is.na(tt), 0, tt)
as.data.frame(t(tt))
3)使用(1)中的data.tab2使用tapply
创建矩阵mat
,然后将其转换为data.frame。如果矩阵足够,则省略最后一行代码。
mat <- with(data.tab2, tapply(V1, list(V2, seq), c, default = 0))
as.data.frame(mat)
有一条评论声称ifelse
比建议的替代方案要慢,但对其进行基准测试并没有显示问题数据的总体差异。当然,性能在这里可能并不是很重要。
library(rbenchmark)
benchmark(
ifelse = {
tt <- do.call("cbind", lapply(unstack(data.tab), ts))
tt[] <- ifelse(is.na(tt), 0, tt)
as.data.frame(t(tt))
},
replace = {
tt <- do.call("cbind", lapply(unstack(data.tab), ts))
tt[is.na(tt)] <- 0
as.data.frame(t(tt))
}
)[1:4]
给予:
test replications elapsed relative
1 ifelse 100 0.25 1
2 replace 100 0.25 1
答案 2 :(得分:2)
使用df
代替data.tab
作为名称:
MAX <- max(table(df$V2))
t(sapply(split(df$V1, df$V2), function(x) c(x, rep(0, MAX-length(x)))))
(想法是将V1分成由V2定义的组,通过在必要时在末尾添加0
来使向量的长度相等,然后将其组合成单个矩阵。{{1} }自动但按列进行最后一位处理,因此需要sapply
。)
t
length<-
还有一个(不太可读的)单行代码在做同样的事情:
U <- unstack(df) # a hack learned from G.Grothendieck's answer
U <- with(df, split(V1,V2)) # more readable version of the above
M <- max(lengths(U))
R <- t(sapply(U, "length<-", M)) # setting all lengths equal
replace(R, is.na(R), 0) # replacing NAs by zeroes
答案 3 :(得分:0)
使用data.table
的转置
cbind(sort(unique(data.tab$V2)),do.call(rbind,transpose(transpose(split(data.tab$V1, data.tab$V2), 0))))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#[1,] 1 644 76 78 350 45 0 0 0
#[2,] 2 37 366 46 0 0 0 0 0
#[3,] 3 71 28 97 30 55 65 116 30
#[4,] 4 18 143 99 0 0 0 0 0