2013-10-09 4 views
1

Я много раз искал в Интернете и не видел ответа на этот конкретный вопрос (я думаю).R, применяя функцию к подмножеству кадра данных

Лучший способ объяснить себя будет с помощью некоторого кода, который реплицирует мою проблему. я сделал некоторые временный данные:

x <- runif(100,1,2) 
y <- runif(100,2,3) 

z <- c(rep(1,100)) 
temp <- cbind(x,y,z) 

temp[1:25,3] = temp[1:25,3] +2 

temp <- as.data.frame(temp) 

И это то, что температура выглядит

  x  y z 
1 1.512620 2.552271 3 
2 1.133614 2.455296 3 
3 1.543242 2.490120 3 
4 1.047618 2.069474 3 
.  .  .  . 
.  .  .  . 
27 1.859012 2.687665 1 
28 1.231450 2.196395 1 

и не продолжать до конца кадра данных (100 строк).

Что я хочу сделать, это применить функцию к кадру данных, но к подмножествам данных. Так, например, я хочу применить значение функции к столбцам x и y для z = 3 и применить среднюю функцию к столбцам x и y для, когда z = 1. Таким образом, я получаю 4 значения: среднее значение x при z = 1 и при z = 3 и среднее значение y при z = 1 и z = 3. Для моего фактического набора данных количество строк, когда z = некоторое значение, сильно варьируется.

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

x <- c(unique(temp$z)) 

Я использую это ^^ для получения уникальных значений z (в данном случае z = 3 и z = 1).

for(i in x){ 
    assign(paste("newdata",i,sep=""),subset(temp[which(temp$z==i),],select=c("x","y"))) 
} 

Так что теперь есть два новых кадров данных newdata1 и newdata3, которые не имеют одинаковое количество строк. newdata1 имеет все значения, когда z = 1, а newdata3 имеет все значения при z = 3.

library(gdata) 

blah <-cbindX(newdata1,newdata3) 

Я использую cbindX для объединения подмножеств данных в один большой фрейм данных. Я не уверен, почему я это делаю точно (я давно это сделал). Все, что я помню, это единственный способ заставить его работать, когда я использую цикл for выше. Основная проблема с кодом заключается в том, что когда у меня есть несколько значений z, тогда вручную печатать в этом списке становится очень громоздким. Если г колебалась от 1 до 50, то пользователь должен ввести в newdata1, newdata2, newdata3 .... и т.д.

... Но это не работа:

summ.test <- apply(blah,2,function(x) { 
c(min(x,na.rm=TRUE),median(x,na.rm=TRUE),max(x,na.rm=TRUE),sum(!is.na(x)))}) 

     x   y   x   y 
[1,] 1.028332 2.018162 1..009595 
[2,] 1.509049 2.504000 1.427981 2.455296 
[3,] 1.992704 2.998483 1.978359 2.970695 
[4,] 75.000000 75.000000 25.000000 25.000000 

Так что я фактически сделал это создать новый кадр данных со значениями, которые я подмножал ранее, и применил интересующие их функции. Таким образом, первая строка: среднее значение x, когда z = 1, среднее значение y при z = 1, среднее значение x при z = 3, среднее значение y при z = 3.

Основные проблемы, которые должны быть достаточно очевидными: метод for loop для подмножества кадра данных вызывает больше проблем, чем я надеюсь. Любые рекомендации, чтобы избежать этого полностью и все же в конечном итоге с тем же результатом?

Пожалуйста, дайте мне знать, если что-то из этого сбивает с толку, или если мой код просто небрежный! Все еще работаю над форматированием вопросов на этом сайте.

ответ

2
> aggregate(. ~ z, data=temp, FUN=mean) 
    z  x  y 
1 1 1.505304 2.474642 
2 3 1.533418 2.477191 

Когда вы будете применять ту же функцию для нескольких столбцы в категориях другого столбца думают об «агрегате». Это версия taht принимает аргумент формулы, где «точка» перед тильдой говорит, чтобы получить среднее значение всех столбцов, кроме «z».

+0

Отлично. Спасибо. Кажется, что совокупность лучше всего подходит для набора данных, особенно потому, что я знаю, что позже буду выполнять более широкие функции. Кажется, что это работает 'aggregate (x ~ z, data = temp, FUN = function (x) c (mn = min (x, na.rm = TRUE), sum (! Is.na (x))))' для несколько функций. Я в идеале хочу сделать регрессию для множества разных значений подмножества, поэтому я увижу, могу ли я настроить сборку, чтобы это сделать. Спасибо. –

3
library(data.table) 
DT <- as.data.table(temp) 
DT[, lapply(.SD, mean), by=z] 
    z  x  y 
1: 3 1.515801 2.309161 
2: 1 1.509637 2.532575 

Или с помощью базы R:

with(temp, cbind(x=tapply(x, z, mean), y=tapply(y, z, mean))) 
     x  y 
1 1.509637 2.532575 
3 1.515801 2.309161 

PS, не забудьте установить семя, set.seed(1) для примеров;)

+0

Это также хорошо работает. Спасибо за ответ и подсказку! –

1

Что я хочу сделать, это применить функцию к кадру данных, но к подмножествам данных.

Таким образом, вы можете использовать subset или aggregate функцию:

data = data.frame(x = runif(100), y = runif(100), z = sample(1:10, 100, replace = TRUE)) 

# get z > 3 AND z < 6 subset, for example 
new.data = subset(data, z > 3 & z < 6) ## CAUTION: use &, not && 

# use newdata 
cm = colMeans(new.data) 
print(cm) 

#  x   y   z 
# 0.4674450 0.5293915 4.5769231 

Надеется, что это помогает!

Смежные вопросы