Как переписать цикл R, взяв в среднем каждые 15 наблюдений в один и тот же код, но без цикла - PullRequest
0 голосов
/ 26 февраля 2019

Я имею дело с огромным набором данных (годы наблюдений за использованием энергии с интервалом в 1 минуту).Я хочу преобразовать его из 1-минутного интервала в 15-минутный.

Я написал цикл for, который делает это успешно (проверено на небольшом подмножестве данных);однако, когда я попытался запустить его на основных данных, он выполнялся очень медленно - и мне потребовалось бы более 175 часов, чтобы выполнить полный цикл (я остановил его в середине выполнения).

Данные, которые будут преобразованы в 15-минутный интервал, - это использование кВтч;таким образом, для его преобразования просто требуется взять среднее из первых 15-ых наблюдений, затем второго 15-го и т. д. Вот этот цикл работает:

# Opening the file
data <- read.csv("1.csv",colClasses="character",na.strings="?")

# Adding an index to each row
total <- nrow(data)
data$obsnum <- seq.int(nrow(data))

# Calculating 15 min kwH usage
data$use_15_min <- data$use
for (i in 1:total) {
  int_used <- floor((i-1)/15)
  obsNum <- 15*int_used
  sum <- 0
  for (j in 1:15) {
    usedIndex <- as.numeric(obsNum+j)
    sum <- as.numeric(data$use[usedIndex]) + sum
  }
  data$use_15_min[i] <- sum/15
}

Я искал функцию, которая может сделать то же самое,но без использования петель, как я полагаю, это должно сэкономить много времени.Тем не менее, я не смог найти один.Как можно достичь той же функциональности без использования цикла?

Ответы [ 3 ]

0 голосов
/ 26 февраля 2019

Потенциальное решение состоит в том, чтобы вычислить текущее среднее (например, используя TTR :: runMean), а затем выбрать каждые 15-е наблюдения.Вот пример:

df = data.frame(x = 1:100, y = runif(100))
df['runmean'] = TTR::runMean(df['y'], n=15)
df_15 = df[seq(1,nrow(df), 15), ]

Я не могу проверить это, так как у меня нет Ваших данных, но возможно:

total <- nrow(data)
data$use_15_min = TTR::runMean(data$use, n=15)
data_15_min = data[seq(1, nrow(df), 15)]
0 голосов
/ 26 февраля 2019

Я бы использовал lubridate::floor_date для создания 15-минутных группировок.

library(tidyverse)
library(lubridate)

df <- tibble(
  date = seq(ymd_hm("2019-01-01 00:00"), by = "min", length.out = 60 * 24 * 7),
  value = rnorm(n = 60 * 24 * 7)
)

df
#> # A tibble: 10,080 x 2
#>    date                  value
#>    <dttm>                <dbl>
#>  1 2019-01-01 00:00:00  0.182 
#>  2 2019-01-01 00:01:00  0.616 
#>  3 2019-01-01 00:02:00 -0.252 
#>  4 2019-01-01 00:03:00  0.0726
#>  5 2019-01-01 00:04:00 -0.917 
#>  6 2019-01-01 00:05:00 -1.78  
#>  7 2019-01-01 00:06:00 -1.49  
#>  8 2019-01-01 00:07:00 -0.818 
#>  9 2019-01-01 00:08:00  0.275 
#> 10 2019-01-01 00:09:00  1.26  
#> # ... with 10,070 more rows

df %>%
  mutate(
    nearest_15_mins = floor_date(date, "15 mins")
  ) %>%
  group_by(nearest_15_mins) %>%
  summarise(
    avg_value_at_15_mins_int = mean(value)
  )
#> # A tibble: 672 x 2
#>    nearest_15_mins     avg_value_at_15_mins_int
#>    <dttm>                                 <dbl>
#>  1 2019-01-01 00:00:00                  -0.272 
#>  2 2019-01-01 00:15:00                  -0.129 
#>  3 2019-01-01 00:30:00                   0.173 
#>  4 2019-01-01 00:45:00                  -0.186 
#>  5 2019-01-01 01:00:00                  -0.188 
#>  6 2019-01-01 01:15:00                   0.104 
#>  7 2019-01-01 01:30:00                  -0.310 
#>  8 2019-01-01 01:45:00                  -0.173 
#>  9 2019-01-01 02:00:00                   0.0137
#> 10 2019-01-01 02:15:00                   0.419 
#> # ... with 662 more rows
0 голосов
/ 26 февраля 2019

Попробуйте data.table:

library(data.table)

DT <- data.table(data)
n <- nrow(DT)
DT[, use_15_min := mean(use), by = gl(n, 15, n)]

Примечание

В вопросе отсутствуют входные данные, поэтому мы использовали это:

data <- data.frame(use = 1:100)
...