for循环和索引的替代方法?

时间:2013-10-05 18:55:52

标签: r for-loop indexing

我有一个包含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循环的车辙和日期和订单的索引上。

2 个答案:

答案 0 :(得分:0)

我会按照以下方式去做:

  1. 确保Order是一个因素。
  2. 对于每个订单,您现在遇到了一个子问题:
    1. date对子数据框进行排序。
    2. 每个Discharge - 均值可以“vectorally”生成: colMeans(cbind(c(Discharge[-1], NA), Discharge, c(NA, Discharge[-length(Discharge)])))
  3. 子问题可以用简单的for循环或函数by来处理。我更希望by
  4. 您的数据已重新排列,但您可以轻松重新排序。
  5. 对于2.2点,想象一下(或尝试一下)一个简单的向量,看看cbind操作的效果。它还迫使你考虑极限情况;如何计算第一个和最后一个排放值(没有先前或进行日期)。

答案 1 :(得分:0)

有几种方法可以解决您的特定困境,但遇到慢for循环时要问的基本问题是,“如何使用矢量化来替换此循环?” (好吧,也许你应该首先问“我应该......?”。)在你的情况下,你是在循环日期,但没有必要明确地这样做,因为只需抓住{{1}的所有行将隐含地抓住所有日期。

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

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

要获取新值,您需要并行平均值。 R没有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 功能,但您可以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%值的工作。

请注意,这假设您的数据已订购。