计算意味着来自非零项的时间序列数据

时间:2015-06-20 17:07:57

标签: r subset

我有一个400+标记名称的数据框,其中包含每个标记的每日时间序列数据。某些标签的值为0,我没有读数。我想计算时间序列中每个标签的非零金额的平均值,并用该平均值填充零值。

示例

tag1   day1   400  
tag1   day2   200  
tag1   day3   0  
.  
.  
tag1  dayn    0  
tag2  day1    0  
tag2  day2    100  
tag2  day3    0  
...  

这里我想用100填充tag2的0值,用300填充tag1的0值

我可以使用ddply对数据框进行子集化并计算均值,但我正在寻找基于每个标记的非零条目获取均值的最佳方法,然后用均值填充数据框中的原始零值每个标签的值。似乎有一些方法可以做一些代码行,但我怀疑有更多更快/更优雅的方法。数据中有400-500个标签,每日读数约为150个

3 个答案:

答案 0 :(得分:2)

对于大型数据集,使用data.tabledplyr可能效率很高。

使用data.table,我们将'data.frame'转换为'data.table'(setDT(df1)),以避免因'Amount'的class之间可能不匹配而发生冲突和mean值(可能是'数字'类),我们可以先将'金额'更改为'数字'类(Amount := as.numeric(Amount)),通过获取{{1}创建'均值'列根据'tag'分组的所有非零'Amount'值,将Amount(mean)的值'0'替换为'Mean'列(Amount==0)中的相应值,如果需要,我们可以通过指定'NULL'

来删除'Mean'列
Amount := Mean

或者使用 library(data.table) setDT(df1)[, Amount:= as.numeric(Amount) ][, Mean:= mean(Amount[Amount!=0]), by= tag ][Amount==0, Amount := Mean][, Mean:= NULL] ,我们可以按'代码'进行分组,并使用dplyr将'0'值更改为replace

mean

或可能的 library(dplyr) df1 %>% group_by(tag)%>% mutate(Amount= replace(Amount, which(Amount==0), mean(Amount[Amount!=0]))) 解决方案

sqldf

更新

如@Frank所述(在评论中),如果某个特定的“标记”组只有0作为“金额”,那么之前的解决方案将获得 library(sqldf) res1 <- sqldf("select * from df1 left join (select tag, avg(Amount) as Mean from df1 where Amount is not 0 group by tag) using (tag)") sqldf("select tag, day, case when Amount like 0 then Mean else Amount end Amount from res1") 的“NaN”。在这种情况下,我不确定预期值是多少。假设我们需要将其保持为0,代码中的更改(包含mean可能的NA值)

na.rm=TRUE

数据

  df2 <- rbind(df1,list("tag3","day3",0))
  setDT(df2)[, Amount := as.numeric(Amount)
  ][,  Mean:= if(all(Amount==0)) 0 
              else mean(Amount[Amount!=0], na.rm=TRUE), by = tag
  ][Amount==0, Amount:= Mean][, Mean:= NULL]

答案 1 :(得分:2)

以下是一些方法:

1)sqldf 这是从评论中删除的。以下代码选择tagdayAmount的两个值之一。对于每一行,如果Amount为0,则它​​运行内部相关选择,否则使用Amount值。

library(sqldf)
sqldf("select 
           tag, 
           day, 
           case when a.Amount = 0 
                then (select avg(b.Amount) 
                      from df1 b 
                      where b.Amount != 0 and b.tag = a.tag) 
                else a.Amount 
                end Amount 
           from df1 a") 

,并提供:

   tag  day Amount
1 tag1 day1    400
2 tag1 day2    200
3 tag1 day3    300
4 tag1 dayn    300
5 tag2 day1    100
6 tag2 day2    100
7 tag2 day3    100

2)na.aggregate 用NA替换零值,然后使用na.aggregateave从动物园应用到每个组:

library(zoo)
transform(df1, Amount = ave(replace(Amount, Amount == 0, NA), tag, FUN = na.aggregate))

注意我们使用以下内容作为输入:

df1 <- structure(list(tag = c("tag1", "tag1", "tag1", "tag1", "tag2", 
"tag2", "tag2"), day = c("day1", "day2", "day3", "dayn", "day1", 
"day2", "day3"), Amount = c(400L, 200L, 0L, 0L, 0L, 100L, 0L)), .Names = c("tag", 
"day", "Amount"), class = "data.frame", row.names = c(NA, -7L))

更新:已添加(2)。

答案 2 :(得分:0)

以下是使用ave()的可能解决方案:

set.seed(2); NT <- 4; ND <- 4; df <- data.frame(tag=rep(paste0('tag',1:NT),each=ND),day=rep(paste0('day',1:ND),NT),amount=c(sample(seq(0,400,100),ND*(NT-1),replace=T),rep(0,ND)));
df;
##     tag  day amount
## 1  tag1 day1      0
## 2  tag1 day2    300
## 3  tag1 day3    200
## 4  tag1 day4      0
## 5  tag2 day1    400
## 6  tag2 day2    400
## 7  tag2 day3      0
## 8  tag2 day4    400
## 9  tag3 day1    200
## 10 tag3 day2    200
## 11 tag3 day3    200
## 12 tag3 day4    100
## 13 tag4 day1      0
## 14 tag4 day2      0
## 15 tag4 day3      0
## 16 tag4 day4      0
df$amount[df$amount==0] <- NA;
df$amount[is.na(df$amount)] <- ave(df$amount,df$tag,FUN=function(x) mean(x,na.rm=T))[is.na(df$amount)];
df;
##     tag  day amount
## 1  tag1 day1    250
## 2  tag1 day2    300
## 3  tag1 day3    200
## 4  tag1 day4    250
## 5  tag2 day1    400
## 6  tag2 day2    400
## 7  tag2 day3    400
## 8  tag2 day4    400
## 9  tag3 day1    200
## 10 tag3 day2    200
## 11 tag3 day3    200
## 12 tag3 day4    100
## 13 tag4 day1    NaN
## 14 tag4 day2    NaN
## 15 tag4 day3    NaN
## 16 tag4 day4    NaN

弗兰克关于NaNs的评论(关于akrun的帖子)也适用于此。如果您不想要NaN,我只需将其替换为零或NA或您想要的任何默认值,例如: df$amount[is.nan(df$amount)] <- NA;