我有一个像这样的数据框
Tag Date (DD/MM/YYYY)
AA 1/1/2010
AB 2/1/2010
AC 3/1/2010
AA 4/1/2010
AB 5/1/2010
AA 6/1/2010
AB 7/1/2010
AC 8/1/2010
现在,有不同数量的不同标签,(平均不到10个)。我需要的是以更加舒适的方式处理数据。我已经对标签序列数据进行了分析,以找出更频繁重复的模式,在这种情况下它将是(AA,AB,AC)。
现在,我想要的是将数据转换为这样的数据,因此我可以使用它。
AA AB AC
1/1/2010 2/1/2010 3/1/2010
4/1/2010 5/1/2010 NA
6/1/2010 7/1/2010 8/1/2010
我已经看到了这个问题,Turning field values into column names in an R data frame,这与我的需求非常接近。这样做
>libray(reshape2)
>df<-sqldf("SELECT Tag, Date FROM validData")
>head(dcast(df,Date~Tag))
产量
Using Date as value column: use value_var to override.
Aggregation function missing: defaulting to length
Date AF687A AVISOO B32D76 B3DC39 B52C72 DF7EAD DF8E83 DFA521 DFA91A
1 2010-12-23 09:18:50 0 0 0 0 1 0 0 0 0
2 2010-12-23 09:18:52 1 0 0 0 0 0 0 0 0
3 2010-12-23 09:18:54 0 0 0 0 1 0 0 0 0
4 2010-12-23 09:18:57 1 0 0 0 0 0 0 0 0
5 2010-12-23 09:18:58 0 0 0 0 1 0 0 0 0
6 2010-12-23 09:19:00 0 0 0 1 0 0 0 0 0
我认为我很接近,但我无法弄清楚最后一步,就像在上面描述的压缩表格一样。有线索吗?
答案 0 :(得分:6)
我要计算Date
列中Tag
列中的unique
所在的行和列,然后填充新矩阵。
首先为每一行设置要匹配的模式;我将使用pat <- unique(df$Tag)
的结果。如果第一组缺少值(除了最后一个值),这将无法正常工作。
col <- match(df$Tag, pat)
row <- cumsum(c(0,diff(col))<=0)
然后通过将标记与模式匹配来计算列,并通过注意新模式何时开始来计算行。
out <- matrix(nrow=max(row), ncol=max(col))
colnames(out) <- pat
out[cbind(row, col)] <- df$Date
然后创建矩阵并填满它!
> out
AA AB AC
[1,] "1/1/2010" "2/1/2010" "3/1/2010"
[2,] "4/1/2010" "5/1/2010" NA
[3,] "6/1/2010" "7/1/2010" "8/1/2010"
结果是
{{1}}
答案 1 :(得分:1)
虽然您在问题中描述了一个表格,但在我看来,您确实想要制作一个列表。您可以使用拆分功能执行此操作:
split(df, df$Tag)
$AA
Tag Date
1 AA 1/1/2010
4 AA 4/1/2010
6 AA 6/1/2010
$AB
Tag Date
2 AB 2/1/2010
5 AB 5/1/2010
7 AB 7/1/2010
$AC
Tag Date
3 AC 3/1/2010
8 AC 8/1/2010
要删除每个列表中的标记列,您可以组合使用lapply
和split
:
lapply(split(df, df$Tag), function(x)x$Date[drop=TRUE])
$AA
[1] 1/1/2010 4/1/2010 6/1/2010
Levels: 1/1/2010 4/1/2010 6/1/2010
$AB
[1] 2/1/2010 5/1/2010 7/1/2010
Levels: 2/1/2010 5/1/2010 7/1/2010
$AC
[1] 3/1/2010 8/1/2010
Levels: 3/1/2010 8/1/2010
答案 2 :(得分:1)
我的回答使用了许多令人讨厌的编码(即两个嵌套循环)来获得所需的解决方案,但它可以为您提供您想要的内容:
df <- structure(list(Tag = c("AA", "AB", "AC", "AA", "AB", "AA", "AB",
"AC"), Date = c("1/1/2010", "2/1/2010", "3/1/2010", "4/1/2010",
"5/1/2010", "6/1/2010", "7/1/2010", "8/1/2010")), .Names = c("Tag",
"Date"), class = "data.frame", row.names = c(NA, -8L))
l <- nrow(df)
counter <- 1
cols <- c("AA", "AB", "AC")
fin <- data.frame(AA = NULL, AB = NULL, AC = NULL)
tmp <- data.frame(AA = NA, AB = NA, AC = NA)
while(counter < l) {
tmp <- data.frame(AA = NA, AB = NA, AC = NA)
for (col in 1:3) {
if (df[counter,1] == cols[col]) {
tmp[1,col] <- df[counter,2]
counter <- counter + 1
}
}
fin <- rbind(fin, tmp)
}
fin
给你:
AA AB AC
1 1/1/2010 2/1/2010 3/1/2010
2 4/1/2010 5/1/2010 <NA>
3 6/1/2010 7/1/2010 8/1/2010
请注意,您可以使用cols <- unique(sort(df[,1]))
获得更通用的解决方案(for (col in 1:3)
,并且需要相应地更改fin
和tmp
的创建。
此外,这种解决方案根本没有内存效率或任何东西。如果您预先分配等等(在更大的数据框架上),您将获得巨大的改进,但是为了快速而肮脏的方式,它可以工作。
答案 3 :(得分:1)
@Andrie非常接近解决方案
# here assumed length 3
# but you can calculate it as max
do.call(cbind,lapply(split(mdf$Date,mdf$Tag),"[",seq(3)))
AA AB AC
[1,] "1/1/2010" "2/1/2010" "3/1/2010"
[2,] "4/1/2010" "5/1/2010" "8/1/2010"
[3,] "6/1/2010" "7/1/2010" NA
编辑(第一个解决方案未考虑模式
mdf$grp <- cumsum(1*c(TRUE,diff(as.numeric(factor(mdf$Tag)))<=0))
reshape(mdf,direction="wide",idvar="grp",timevar="Tag")
grp Date.AA Date.AB Date.AC
1 1 1/1/2010 2/1/2010 3/1/2010
4 2 4/1/2010 5/1/2010 <NA>
6 3 6/1/2010 7/1/2010 8/1/2010