Функция или цикл для подмножества скользящего среднего в R

Я новичок в циклах и функциях в R.

Представьте, что у меня есть измерения через каждые 0,1 единицы от 1,0 до 3,5 для четырех образцов (A, B, C, D).

Я хочу найти средние значения (+/- 0,2 единицы) около 1,5, 2,5 и 3,5. Итак, для 1.5 я усредняю ​​значения c (1.3, 1.4, 1.5, 1.6 и 1.7) и т. Д.

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

X <- (1.5, 2.5, 3.5)

for (i in X)

{
  avg <- colMeans(subset(data,data$measurement > (i - 0.2) & data$measurement < (i + 0.2)))   
}

Я также подумал об использовании '[':

colMeans(data[data$measurement > (i-0.2) & data$measurement < (i+0.2)]) 

Спасибо за помощь, sqldf - действительно хороший инструмент, пример делает именно то, что я хочу!

Однако я не могу заставить его работать с реальным набором данных. Я изменил код так, чтобы он выглядел (извините, это больше не соответствует образцу данных):

M <- sqldf("select r.i,avg(w.X1),avg(w.X2),avg(w.X3),avg(w.X4)
           from Y r, Y w
           where w.i betreen r.i - 1 and r.i + 1
           group by r.i
           having r.i+0.0 in (600, 700, 800)")

Чтобы контекстуализировать это, я пытаюсь суммировать среднее значение всех точек из 599–601, 699–701 и 799–801 для четырех столбцов с именами X1, X2, X3, X4. Я назвал этот фрейм данных «Y». Строки на самом деле являются длинами волн, а данные указывают количество света, отраженного на этой длине волны.

Вы видите что-то не так с приведенным выше кодом? - Он создает матрицу с правильными размерами, но средние значения не совпадают с тем, что они должны быть из более крупного набора данных. Мне интересно, не понимаю ли я чего-то в коде, например, важности переменной 'w'.


person Sarah Grogan    schedule 25.03.2015    source источник
comment
Было бы намного проще использовать cut для создания группирующей переменной, а затем использовать tapply(vals, group, mean). Тогда вы не потеряете кучу данных в 1.8, 1.9, 2.0, 2.1 и 2.2. Вам действительно следует опубликовать пример набора данных.   -  person IRTFM    schedule 26.03.2015


Ответы (1)


Правильная индексация выполняется быстрее, чем цикл.

library(zoo)
set.seed(1)
x <- as.character(seq(1,3.5,.1)) 
z <- zoo(data.frame(a=rnorm(length(x)),
                    b=rnorm(length(x)),
                    c=rnorm(length(x))),
         x)
z2 <- rollmean(z, k = 5, align = "center")[as.character(seq(1,3.5,.5)),]
> z2
              a           b          c
1.5  0.46601479  0.40153999  0.2007418
2    0.31015536 -0.22912642  0.4673692
2.5 -0.04141133  0.31978341  0.4350507
3    0.63816023 -0.07509644 -0.3622883

> data.frame(z2, index = index(z2))
              a           b          c index
1.5  0.46601479  0.40153999  0.2007418   1.5
2    0.31015536 -0.22912642  0.4673692     2
2.5 -0.04141133  0.31978341  0.4350507   2.5
3    0.63816023 -0.07509644 -0.3622883     3

Если вы хотите частичные заливки по краям, где ширина окна меньше 5:

> rollapply(z, width = 5, align = "center", partial = TRUE, FUN = mean)[as.character(seq(1,3.5,.5)),]
              a           b           c
1   -0.42614637 -0.70156598  0.21492677
1.5  0.46601479  0.40153999  0.20074176 
2    0.31015536 -0.22912642  0.46736921 
2.5 -0.04141133  0.31978341  0.43505071
3    0.63816023 -0.07509644 -0.36228832
3.5 -0.47521823  0.22239574 -0.05024676

Если размеры окон нерегулярны, но расположены на одинаковом расстоянии, как указано в комментарии:

> z2 <- as.data.frame(z)
> z2$i <- row.names(z2)
> library(sqldf)
> sqldf("select a.i,avg(b.a),avg(b.b),avg(b.c) 
         from z2 a, z2 b 
         where b.i between a.i - .21 and a.i + .21 
         group by a.i 
         having a.i+0.0 in (1.5,2.0,2.5,3.0,3.5)")
    i    avg(b.a)    avg(b.b)    avg(b.c)
1 1.5  0.46601479  0.40153999  0.20074176
2   2  0.31015536 -0.22912642  0.46736921
3 2.5 -0.04141133  0.31978341  0.43505071
4   3  0.63816023 -0.07509644 -0.36228832
5 3.5 -0.47521823  0.22239574 -0.05024676
person nh2    schedule 26.03.2015
comment
Спасибо, это очень помогло. - person Sarah Grogan; 26.03.2015
comment
Мне интересно, что, если значения, которые вы измеряете, менее систематичны, а ширина немного изменится? Например, если строки не каждые 0,1 единицы, а что-то вроде: 1,02, 1,11, 1,25, 1,31, 1,39, 1,52, 1,66, 1,73, 1,79, 1,80, 1,92, ... Если числа менее систематичны, для средних значений в том же диапазоне (например, 1,3–1,7), иногда будет немного больше или меньше значений. И в этом примере, если вы хотите оценить 1,5; это значение не совсем в наборе, и 1,52 является ближайшим значением. Есть предположения? - person Sarah Grogan; 26.03.2015
comment
В этом случае было бы проще использовать SQL. См. Добавленный пример. - person nh2; 27.03.2015
comment
Спасибо за отличный пример с использованием sqldf! Ваш пример работает отлично, однако, когда я применяю его к своим реальным данным, результаты не имеют смысла. Вы видите какие-либо проблемы в коде, который я добавил к исходному вопросу? Может я неправильно понимаю команду. - person Sarah Grogan; 27.03.2015
comment
Это может быть числовая точность. Попробуйте r.i +/- 1.01 вместо +/- 1, чтобы убедиться, что вы захватываете все строки. В противном случае он мог бы выполнить dput (head (Y)) с несколькими строками ваших фактических данных. - person nh2; 28.03.2015
comment
Кроме того, для диагностики можно удалить все из группы с помощью ... Далее и проверить, чтобы убедиться, что вы присоединяетесь к нужным строкам. - person nh2; 28.03.2015