1

我有一个包含 3 列的大型数据集,Order、Discharge、Date(数字)。每个订单有 20 年的每日排放值,可以超过 100。

> head(dat)
      Order Discharge date
         1   0.04712 6574
         2   0.05108 6574
         3   0.00000 6574
         4   0.00000 6574
         5   3.54100 6574
         6   3.61500 6574

对于给定的订单 x,我想用该日期 x+1 和 x-1 处的出料平均值替换出料值。我一直在使用 for 循环和索引以粗略的方式执行此操作,但处理需要一个多小时。我知道必须有更好的方法。

    x <- 4
    for(i in min(dat[,3]):max(dat[,3]))
    dat[,2][dat[,3] == i & dat[,1] == x ] <- 
    mean(c(dat[,2][dat[,3] == i & dat[,1] == x + 1], 
    dat[,2][dat[,3] == i & dat[,1] == x - 1]))

> head(dat)
    Order Discharge date
       1   0.04712 6574
       2   0.05108 6574
       3   0.00000 6574
       4   1.77050 6574
       5   3.54100 6574
       6   3.61500 6574

如果第 4 号订单的出院,日期 6574 已替换为 1.77050。它有效,但速度非常慢。

我应该指定我不需要对每个订单进行此计算,而只需选择少数几个(总共 117 个订单中只有 8 个)。根据答案,我有以下内容。

    dat$NewDischarge <- by(dat$Discharge,dat$date,function(x) 
    colMeans(cbind(c(x[-1],NA), x, 
    c(NA, x[-length(x)])), na.rm=T)) 

我试图找出一种方法,仍然只计算要计算的选择订单的值,并且陷入 for 循环和日期和订单索引的常规。

4

2 回答 2

0

有几种方法可以解决您的特定困境,但是当遇到慢for循环时要问的基本问题是,“我如何使用矢量化来替换这个循环?” (好吧,也许您应该首先问“我应该...吗?”。)在您的情况下,您正在循环遍历日期,但是没有必要显式地这样做,因为只需抓取所有行将dat$Order==x隐式抓取所有日期。

您发布的数据集只有一个日期,但我可以生成一些假数据来说明:

generate.data <- function(n.order, n.date){
  dat <- expand.grid(Order=seq_len(n.order), date=seq_len(n.date))
  dat$Discharge <- rlnorm(n.order * n.date)
  dat[, c("Order", "Discharge", "date")]
}

dat <- generate.data(10, 5)

head(dat)
#   Order Discharge date
# 1     1 2.1925563    1
# 2     2 0.4093022    1
# 3     3 2.5525497    1
# 4     4 1.9274013    1
# 5     5 1.1941986    1
# 6     6 1.2407451    1
tail(dat)
#    Order Discharge date
# 45     5 1.4344575    5
# 46     6 0.5757580    5
# 47     7 0.4986190    5
# 48     8 1.2076292    5
# 49     9 0.3724899    5
# 50    10 0.8288401    5

以下是所有日期中 的所有行dat$Order==4

dat[dat$Order==4, ]
#    Order Discharge date
# 4      4 1.9274013    1
# 14     4 3.5319072    2
# 24     4 0.2374532    3
# 34     4 0.4549798    4
# 44     4 0.7654059    5

您可以只选择该Discharge列,您将获得作业的左侧:

dat[dat$Order==4, ]$Discharge
# [1] 1.9274013 3.5319072 0.2374532 0.4549798 0.7654059

现在你只需要右侧,它有两个组件:x-1放电和x+1放电。您可以像抓住x排放物一样抓住这些:

dat[dat$Order==4-1, ]$Discharge
# [1] 2.5525497 1.9143963 0.2800546 8.3627810 7.8577635
dat[dat$Order==4+1, ]$Discharge
# [1] 1.1941986 4.6076114 0.3963693 0.4190957 1.4344575

要获得新值,您需要平行均值。R 没有pmean功能,但您可以cbind使用这些功能并使用rowMeans

rowMeans(cbind(dat[dat$Order==4-1, ]$Discharge, dat[dat$Order==4+1, ]$Discharge))
# [1] 1.8733741 3.2610039 0.3382119 4.3909383 4.6461105

所以,最后你有:

dat[dat$Order==4, ]$Discharge <- rowMeans(cbind(dat[dat$Order==4-1, ]$Discharge,
                                                dat[dat$Order==4+1, ]$Discharge))

您甚至可以使用它%in%来使这项工作适用于您的所有x价值观。

请注意,这假设您的数据是有序的。

于 2013-10-07T16:58:00.150 回答
0

我会按照以下方式进行:

  1. 确保这Order是一个因素。
  2. 对于每个订单,您现在有一个子问题:
    1. 按 对子数据帧进行排序date
    2. 每个Discharge-mean 可以“矢量地”产生为: colMeans(cbind(c(Discharge[-1], NA), Discharge, c(NA, Discharge[-length(Discharge)])))
  3. 子问题可以通过简单的 for 循环或函数来处理by。我宁愿by.
  4. 您的数据已重新排列,但您可以轻松地重新排序。

对于第 2.2 点,用一个简单的向量想象它(或尝试它)并查看cbind操作的效果。它还迫使您考虑极限情况;如何计算第一个和最后一个排放值(没有之前或进行日期)。

于 2013-10-07T12:33:39.540 回答