通过在R中添加零来塑造数据框

时间:2018-10-05 14:44:25

标签: r dataframe

我有一个数据框,其距离在第一个列中,而类别在第二个列中:

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")

4 个答案:

答案 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