【问题标题】:Get column mean every block on n rows based on condition根据条件获取列平均 n 行上的每个块
【发布时间】:2017-09-29 14:38:02
【问题描述】:

我有这个数据框

       r2 distance
1   33.64    67866
2    8.50    77229
3   15.07   109119
4   24.35   142279 
5    7.74   143393
6    8.21   177670
7   12.26   216440
8   12.66   253751
9   26.31   282556
10  39.08   320816

我需要为distance 列中两个值之间的距离等于或小于100000 的每个行块计算列r2 的平均值。 对于此示例,所需的输出将是:

  mean_r2 diff_of_distance
1   17.86            75527 ## mean of rows 1 to 5; distance 5 - distance 1
2   13.91            66164 ## mean of rows 2 to 5; distance 5 - distance 2
3   13.84            68551 ## mean of rows 3 to 6; distance 6 - distance 3
4   13.14            74161 ## mean of rows 4 to 7; distance 7 - distance 4
5    9.40            73047 ## mean of rows 5 to 7; distance 7 - distance 5
6   11.04            76081 ## mean of rows 6 to 8; distance 8 - distance 6

等等。

编辑 1:我有超过 100,000 行。

谢谢。

【问题讨论】:

  • 您的问题令人困惑,因为您显示了第 2-5 行的平均值,但是 77,229(第 2 行)不在 109119(第 3 行)的 10,000 之内。
  • @AdrianMartin 你说得对,我的意思是 100,000。编辑了问题。

标签: r loops dataframe aggregate apply


【解决方案1】:

循环遍历distance 的每个值,从distance 向量中的值中减去这个值,并测试结果是否小于 100000。这将创建一个布尔向量,您可以将其相加以确定距离所在的索引大于 100000(即 bool 变为 FALSE)。使用此索引来识别您的块,然后在每个块中取 r2 的平均值。

为了加速代码定义你的向量类型和长度(避免在每次迭代中“增长向量”。

means <- vector("numeric", length = nrow(df))
rows <- vector("numeric", length = nrow(df))
distance_diff <- vector("numeric", length = nrow(df))

for (i in seq_along(df$distance)) {

  dis_val <- df$distance[i] # the ith distance value
  bools <- (df$distance - dis_val) < 100000 # bool indicating if difference between i and every value in vector is less than 100000
  block_range <- sum(bools)# taking sum of bools identifies the value at which the distance becomes > 100000
  rows[i] <- paste(as.character(i), "-", as.character(block_range)) 
  means[i] <- mean(df$r2[i:block_range]) # take the mean of r2 in the range i to all rows where distance is < 100000
  distance_diff[i] <- df$distance[block_range] - dis_val # minus the distance from the value before distance is > 100000 from i

}

data.frame(mean_r2 = means, rows= rows, diff_of_distance=distance_diff)

     mean_r2    rows diff_of_distance
1  17.860000   1 - 5            75527
2  13.915000   2 - 5            66164
3  13.842500   3 - 6            68551
4  13.140000   4 - 7            74161
5   9.403333   5 - 7            73047
6  11.043333   6 - 8            76081
7  17.076667   7 - 9            66116
8  26.016667  8 - 10            67065
9  32.695000  9 - 10            38260
10 39.080000 10 - 10                0

【讨论】:

  • 感谢您的代码,它比 Jimbou 的最快,所以我会使用这个。我还有一个好奇心,如何打印与选择用于计算平均值的点的距离差?即第1行到第5行之间计算第一个平均值,如何打印一个新列distance第5行的distance减去第1行的distance?请参阅已编辑的问题。谢谢!
  • 嗨 Pietro,我已经修改了上面的代码来计算这个距离。为此,我们只需从距离值i 中减去距离变为 > 100000 之前的距离值,并将结果存储在一个名为distance_diff的新向量中
  • 我还对代码进行了小修改以加快速度。具体来说,它现在只计算一次 sum(bools) 而不是三次。我还对循环中的每一行进行了注释,以便更清楚地了解它发生了什么。
  • 这太棒了,谢谢!对不起,如果这听起来微不足道,但我现在开始学习 R 中的循环。
  • 没问题,这是一种很好的学习方式——如果您对答案感到满意,您可以接受吗?
【解决方案2】:

你可以试试:

# your data
d <- read.table(text="r2 distance
1   33.64    67866
           2    8.50    77229
           3   15.07   109119
           4   24.35   142279 
           5    7.74   143393
           6    8.21   177670
           7   12.26   216440
           8   12.66   253751
           9   26.31   282556
           10  39.08   320816", header=T)

library(tidyverse) #dplyr_0.7.2
d %>%
  mutate(index=1:n()) %>% add row index
  group_by(index) %>% # group by this index
  # calculate difference and find max row where diff < 100000
  mutate(max_row=max(which(.$distance - distance < 100000, arr.ind=T))) %>% 
  # calculate mean
  mutate(mean_r2=mean(.$r2[index:max_row])) %>% 
  # calculate the difference
  mutate(diff_of_distance=.$distance[max_row] - .$distance[index]) %>% 
  # unite the columns 
  unite(rows, index, max_row, sep = "-")
    # A tibble: 10 x 5
      r2 distance  rows   mean_r2 diff_of_distance
 * <dbl>    <int> <chr>     <dbl>            <int>
 1 33.64    67866   1-5 17.860000            75527
 2  8.50    77229   2-5 13.915000            66164
 3 15.07   109119   3-6 13.842500            68551
 4 24.35   142279   4-7 13.140000            74161
 5  7.74   143393   5-7  9.403333            73047
 6  8.21   177670   6-8 11.043333            76081
 7 12.26   216440   7-9 17.076667            66116
 8 12.66   253751  8-10 26.016667            67065
 9 26.31   282556  9-10 32.695000            38260
10 39.08   320816 10-10 39.080000                0

之所以有效,是因为 group_by 对数据框进行了子集化,因此您可以在 mutate 内访问每个组的相应 distance 值,并使用 .$distance 计算与完整向量的差异,因为无论 group_by()功能。

【讨论】:

  • 感谢您的回答,我目前正在尝试,但它从 10 分钟开始运行。也许 for 循环不适合这个数据框的大小(见编辑 1)。还有其他建议吗?无论如何,感谢您的意见!
  • 请查看我的编辑。我完全修改了代码并切换到使用 dplyr 的解决方案。对于庞大的数据集也应该非常快。
猜你喜欢
  • 1970-01-01
  • 2018-07-31
  • 2016-12-09
  • 1970-01-01
  • 2016-11-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多