【问题标题】:R Language - Sorting data into ranges; averaging; ignore outliersR 语言 - 将数据分类为范围;平均;忽略异常值
【发布时间】:2011-06-18 02:38:17
【问题描述】:

我正在分析来自风力涡轮机的数据,通常这是我在 excel 中会做的事情,但数据量需要一些繁重的东西。我以前从未使用过 R,所以我只是在寻找一些指针。

数据由 2 列 WindSpeedPower 组成,到目前为止,我已经从 CSV 文件导入数据并将两者相互散点图。

接下来我想做的是将数据分类为范围;例如,WindSpeed 介于 x 和 y 之间的所有数据,然后找到每个范围产生的平均功率并绘制形成的曲线。

根据这个平均值,我想根据落在平均值的两个标准差之一内​​的数据重新计算平均值(基本上忽略异常值)。

任何指针表示赞赏。

对于那些感兴趣的人,我正在尝试创建一个类似于this 的图表。它是一种非常标准的图表类型,但就像我说的那样,数据的剪切量需要比 excel 更重的东西。

【问题讨论】:

    标签: r outliers


    【解决方案1】:

    首先,我们将创建一些示例数据以使问题具体化:

    w_sp = sample(seq(0, 100, 0.01), 1000)
    power = 1/(1+exp(-(rnorm(1000, mean=w_sp, sd=5) -40)/5))
    

    假设我们要将power 的值设置在 [0,5)、[5,10) 等之间。然后

    bin_incr = 5
    bins = seq(0, 95, bin_incr)
    y_mean = sapply(bins, function(x) mean(power[w_sp >= x & w_sp < (x+bin_incr)]))
    

    我们现在已经创建了感兴趣范围之间的平均值。请注意,如果您想要中值,只需将 mean 更改为 median。剩下要做的就是绘制它们:

    plot(w_sp, power)
    points(seq(2.5, 97.5, 5), y_mean, col=3, pch=16)
    

    要根据平均值的两个标准差范围内的数据获得平均值,我们需要创建一个稍微复杂的函数:

    noOutliers = function(x, power, w_sp, bin_incr) {
      d = power[w_sp >= x & w_sp < (x + bin_incr)]
      m_d = mean(d)
      d_trim = mean(d[d > (m_d - 2*sd(d)) & (d < m_d + 2*sd(d))])
      return(mean(d_trim))
    }
    
    y_no_outliers = sapply(bins, noOutliers, power, w_sp, bin_incr)
    

    【讨论】:

    • 最好使用mad 而不是sd,这样异常值就不会夸大方差的估计值。
    • 实际上,我会按照您在回答中的建议使用medianloess
    【解决方案2】:

    既然您不再使用 Excel,何不使用一种现代统计方法,该方法不需要对数据进行粗略的分箱,并使用临时方法来去除异常值:由 loess 实现的局部平滑回归。

    对 csgillespie 的样本数据稍作修改:

    w_sp <- sample(seq(0, 100, 0.01), 1000)
    power <- 1/(1+exp(-(w_sp -40)/5)) + rnorm(1000, sd = 0.1)
    
    plot(w_sp, power)
    
    x_grid <- seq(0, 100, length = 100)
    lines(x_grid, predict(loess(power ~ w_sp), x_grid), col = "red", lwd = 3)
    

    【讨论】:

    • 谢谢,我已经采用了这个解决方案。因为它根据我的测试用例给了我正确的结果。
    • 我尝试将其建模为真实数据,但对结果并不完全满意。不幸的是,我无法发布数据,但我已经在myimagespace.com/public/view/full/5617 上提供了图表。尽管它是迄今为止最好的解决方案,但它与数据的关系并不密切。如何“调整”代码以获得更好的拟合曲线?
    • @klonq 我的直接猜测是你可能不能,而不会引入其他问题。让这些本地模型更好地拟合数据的最简单方法是使它们更本地化(在loess() 中减少span 或在gam() 中增加k。但通常情况下,增加的复杂性更适合数据某些区域,但在其他区域过度拟合。因此,我在示例中尝试了自适应平滑器,其中平滑度/粗糙度在拟合范围内变化;曲线在关系变化的地方可能是粗糙的,而在没有变化或变化很小的地方是平滑的.
    【解决方案3】:

    我建议也玩一下 Hadley 自己的 ggplot2。他的网站是一个很好的资源:@​​987654321@。

        # If you haven't already installed ggplot2:
        install.pacakges("ggplot2", dependencies = T)
    
        # Load the ggplot2 package
        require(ggplot2)
    
        # csgillespie's example data
        w_sp <- sample(seq(0, 100, 0.01), 1000)
        power <- 1/(1+exp(-(w_sp -40)/5)) + rnorm(1000, sd = 0.1)
    
        # Bind the two variables into a data frame, which ggplot prefers
        wind <- data.frame(w_sp = w_sp, power = power)
    
        # Take a look at how the first few rows look, just for fun
        head(wind)
    
    
        # Create a simple plot
        ggplot(data = wind, aes(x = w_sp, y = power)) + geom_point() + geom_smooth()
    
        # Create a slightly more complicated plot as an example of how to fine tune
        # plots in ggplot
        p1 <- ggplot(data = wind, aes(x = w_sp, y = power))
        p2 <- p1 + geom_point(colour = "darkblue", size = 1, shape = "dot") 
        p3 <- p2 + geom_smooth(method = "loess", se = TRUE, colour = "purple")
        p3 + scale_x_continuous(name = "mph") + 
                 scale_y_continuous(name = "power") +
                 opts(title = "Wind speed and power")
    

    【讨论】:

      【解决方案4】:

      使用与@hadley 的动机相似的这个版本,使用加法模型和使用包mgcv 的自适应平滑器进行混合:

      @hadley 使用的首先是虚拟数据

      w_sp <- sample(seq(0, 100, 0.01), 1000)
      power <- 1/(1+exp(-(w_sp -40)/5)) + rnorm(1000, sd = 0.1)
      df <- data.frame(power = power, w_sp = w_sp)
      

      使用gam() 拟合加法模型,通过REML 使用自适应平滑器和平滑度选择

      require(mgcv)
      mod <- gam(power ~ s(w_sp, bs = "ad", k = 20), data = df, method = "REML")
      summary(mod)
      

      根据我们的模型进行预测并获得拟合标准误差,使用后者生成大约 95% 的置信区间

      x_grid <- with(df, data.frame(w_sp = seq(min(w_sp), max(w_sp), length = 100)))
      pred <- predict(mod, x_grid, se.fit = TRUE)
      x_grid <- within(x_grid, fit <- pred$fit)
      x_grid <- within(x_grid, upr <- fit + 2 * pred$se.fit)
      x_grid <- within(x_grid, lwr <- fit - 2 * pred$se.fit)
      

      画出一切,黄土适合比较

      plot(power ~ w_sp, data = df, col = "grey")
      lines(fit ~ w_sp, data = x_grid, col = "red", lwd = 3)
      ## upper and lower confidence intervals ~95%
      lines(upr ~ w_sp, data = x_grid, col = "red", lwd = 2, lty = "dashed")
      lines(lwr ~ w_sp, data = x_grid, col = "red", lwd = 2, lty = "dashed")
      ## add loess fit from @hadley's answer
      lines(x_grid$w_sp, predict(loess(power ~ w_sp, data = df), x_grid), col = "blue",
            lwd = 3)
      

      【讨论】:

      • 感谢 Gavin,这是一个更好的解决方案。但是我无法让它工作(1 个错误,1 个警告)
      • eval 中的错误(predvars,data,env):数字 'envir' arg 长度不是 1
      • 由行 pred
      • @klonq 道歉,在您引用的那一行之前缺少一行。将编辑答案以纠正此问题。
      • 嗨,我今天一直在努力解决这个错误几次,不知道您是否可以提供帮助。我什至找不到哪里出了问题,错误是“样条设计错误(knots,x,ord,derivs,outer.ok = outer.ok):'x'数据必须在 -0.0452226 到 22.6226 的范围内除非你设置'outer.ok = TRUE'”我以为我首先通过在我的csv中插入一行来解决它,其中两列的值都是0,但现在错误是指一个负数,我没有负数我的数据
      【解决方案5】:
      猜你喜欢
      • 1970-01-01
      • 2014-02-27
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      • 2019-05-01
      • 2021-04-16
      • 2020-03-11
      • 2020-06-05
      相关资源
      最近更新 更多