我花了4天的时间试图解决这个问题,从其他相关问题中学到了很多,但仍然找不到有效的解决方案。这是:
我有一个包含500k乘40个变量的数据集,需要将变量从长到大转换为两个连续行之间的比较。
数据样本如下:
df <- data.frame(id=c(267, 268, 269, 269, 270, 271, 272, 272, 273, 274),
quant=c(2,1,4,4,1,5,2,2,3,1),
pts= c(3,2,7,11,2,4,5,9,6,4),
kind=c('v','v', 'v', 'c', 'v', 'v', 'v', 'c', 'v','v'))
id quant pts kind
1 267 2 3 v
2 268 1 2 v
3 269 4 7 v
4 269 4 11 c
5 270 1 2 v
6 271 5 4 v
7 272 2 5 v
8 272 2 9 c
9 273 3 6 v
10 274 1 4 v
请注意,每次 id 重复时, quant ,变量 kind 在一行中假定值为“v”,另一个'c'。相反,'c'的值仅出现在具有重复 id 的记录中。
我打算获得以下data.frame:
id quant pts kind c
1 267 2 3 v 0
2 268 1 2 v 0
3 269 4 7 v 11
5 270 1 2 v 0
6 271 5 4 v 0
7 272 2 5 v 9
9 273 3 6 v 0
10 274 1 4 v 0
我使用以下代码弄明白了:
df$c <- 0
df$delete <- 0
for (i in 1:(dim(df)[1] - 1)) {
if (df[i,'id'] == df[i+1, 'id'] & df[i+1, 'kind'] == 'c')
{
df[i, 'c'] <- df[i+1, 'pts']
df[i+1, 'delete'] <- 1
}
}
df <- df[df$delete == 0, ]
df$delete <- NULL
这是令人讨厌和丑陋的,但它确实有效,虽然在原始数据集中需要大约10个小时!
正确代码的任何想法?
非常感谢!
答案 0 :(得分:1)
以下是可用于此示例的基本方法:
df$c <- with(df, ave(pts, id, quant, FUN = function(x) {
ifelse(length(x) == 1, 0, tail(x, 1))
}))
df <- df[df$kind == "v", ]
df
# id quant pts kind c
# 1 267 2 3 v 0
# 2 268 1 2 v 0
# 3 269 4 7 v 11
# 5 270 1 2 v 0
# 6 271 5 4 v 0
# 7 272 2 5 v 9
# 9 273 3 6 v 0
# 10 274 1 4 v 0
顺便说一下,使用data.table
可以让更多更有趣。
以下是数据:
library(data.table)
DT <- data.table(id = c(267, 268, 269, 269, 270, 271, 272, 272, 273, 274),
quant = c(2, 1, 4, 4, 1, 5, 2, 2, 3, 1),
pts = c(3, 2, 7, 11, 2, 4, 5, 9, 6, 4),
kind = c('v','v', 'v', 'c', 'v', 'v', 'v', 'c', 'v','v'),
key = c("id", "quant"))
DT
# id quant pts kind
# 1: 267 2 3 v
# 2: 268 1 2 v
# 3: 269 4 7 v
# 4: 269 4 11 c
# 5: 270 1 2 v
# 6: 271 5 4 v
# 7: 272 2 5 v
# 8: 272 2 9 c
# 9: 273 3 6 v
# 10: 274 1 4 v
以下是您正在寻找的内容:
DT[, c := ifelse(length(pts) == 1, 0, tail(pts, 1)), by = key(DT)][kind == "v"]
# id quant pts kind c
# 1: 267 2 3 v 0
# 2: 268 1 2 v 0
# 3: 269 4 7 v 11
# 4: 270 1 2 v 0
# 5: 271 5 4 v 0
# 6: 272 2 5 v 9
# 7: 273 3 6 v 0
# 8: 274 1 4 v 0
答案 1 :(得分:0)
这是使用包plyr的方法:
DF <- ddply(df, .(id), function(x) cbind(x[1,], c=x$pts[match("c", x$kind)]))
DF$c[is.na(DF$c)] <- 0
# or
DF <- ddply(df, .(id), function(x) cbind(x[1,], c=sum(x$pts*(x$kind=="c"))))