2014-08-27 3 views
1

Я изо всех сил пытаюсь понять, почему я не возвращаю правильные значения в свой кадр данных из своей функции. Я хочу пропустить вектор моего фрейма данных и создать новый столбец путем вычисления внутри элементов вектора. Вот что у меня есть:Функция Loop в R

# x will be the data frame's vector 
y <- function(x){ 
new <- c() 
for (i in x){ 
    new <- c(new, x[i] - x[i+1]) 
} 
return (new) 
} 

Итак, здесь я хочу создать новый вектор, который возвращает следующий элемент, вычитаемый из текущего элемента. Теперь, когда я применяю его к своему кадру данных

df$new <- lapply(df$I, y) 

Я получаю все НС. Я знаю, что мне не хватает чего-то совершенно очевидного ...

Также как я могу выполнить функцию, которая сбрасывает себя, если df $ ID изменяется, поэтому я не вычитаю элементы из двух разных идентификаторов df $? Например, в моем кадре данных будет

ID I Order new 
1001 5 1 1 
1001 6 2 -2 
1001 4 3 -2 
1001 2 4 NA 
1005 2 1 6 
1005 8 2 0 
1005 8 3 -2 
1005 6 4 NA 

Спасибо!

+0

Не должно ли это 'for (i in x)' быть 'for (i in 1: length (x))'? – zx8754

+1

ИМХО Ваша проблема: 'for (i in x)'; 'i' будет проходить через каждый элемент' x', но вы используете 'i' в качестве индекса. Попробуйте, например. 'для (i в seq (вдоль = x))'. Также вы должны подумать о предварительном распределении вашего вектора 'new'. BTW 'diff', как представляется, является той функцией, которую вы ищете. – sgibb

+0

Я подозреваю, что вы не понимаете, что кадры данных являются списками, а x [i] будет целым столбцом, и поэтому вы вычитаете соседние столбцы. Вы также создадите классическую ошибку программирования, когда «i» находится в конце элементов списка, и вы попытаетесь получить «i + 1». –

ответ

2

Избегайте петлю и использовать diff. Все здесь векторизовано, так что это легко.

df$new <- c(diff(df$I), NA) 

Но я не понимаю ваш пример. Почему некоторые значения 0 изменены на NA, а некоторые нет? А не должно 8-2 быть 6 и не -6? Я думаю, что это нужно уточнить.

Если значения 0 необходимо изменить на NA, выполните следующие действия после вышеуказанного кода.

df$new[df$new == 0] <- NA 

Однострочные полного процесса, который возвращает новый кадр данных, может быть

within(df, { new <- c(diff(I), NA); new[new == 0] <- NA }) 

Обновление: Что касается ваших комментариев ниже, мой обновленный ответ следующим образом.

> M <- do.call(rbind, Map(function(x) { x$z <- c(diff(x$I), NA); x }, 
          split(dat, dat$ID))) 
> rownames(M) <- NULL 
> M 
    ID I Order z 
1 1001 5  1 1 
2 1001 6  2 -2 
3 1001 4  3 -2 
4 1001 2  4 NA 
5 1005 2  1 6 
6 1005 8  2 0 
7 1005 8  3 -2 
8 1005 6  4 NA 
+0

Большое спасибо за ваше решение. Вы правы, значение -6 должно быть 6. Причина значений NA заключается в том, что идентификатор изменяется. Поскольку я беру следующий элемент и вычитаю его из элемента перед ним, я не могу вычислить разницу последнего вхождения df $ I df $ ID. Дайте мне знать, если это очистит вас! – herkyonparade

+0

В любом случае, я могу изменить ваш код для учета изменения в df $ ID? Вывод не должен вычитать элементы из разных df $ ID. – herkyonparade

+0

@herkyonparade - тот факт, что вывод не должен вычитать элементы из разных df $ ID, очень важен и не совсем понятен в вашем вопросе. Можете ли вы обновить вопрос с помощью этой информации, пожалуйста? –

1

Вместо того, чтобы петли, вам было бы лучше использовать векторную версию математики. Точные показатели будут зависеть от того, что вы хотите сделать с последним значением ... (Обратите внимание на строку не помещается в ваш for петлю, но только дает результат.)

df$new = c(df$I[-1],NA) - df$I 

Здесь вы будете вычитая оригинал df$I из сдвинутой версии, которая опускает первое значение [-1] и добавляет NA в конце.

EDIT на комментарий: Если вы не хотите, чтобы вычитать через df$ID, вы можете пустые из этого подмножества клеток после вычитания:

df$new[df$ID != c(df$ID[-1],NA)] = NA 
+0

Спасибо, я просто нажал знак «-», чтобы вернуть результаты, которые я хотел, потому что он вычитал оригинал из следующего элемента. В любом случае, я могу отредактировать ваш код для учета изменений в df $ ID? Вывод не должен вычитать элементы из разных идентификаторов df $. Я ценю ваш ответ! – herkyonparade

+0

Вы также можете поменять порядок элементов 'df $ I = c (...)' для вычитания второго с первого раза. У меня это было изначально, но я изменил его в соответствии с вашими результатами. Итак, вы хотите, чтобы NAs для последнего элемента в каждом списке ...? Я добавил заявление, чтобы сделать это, хотя есть много способов решить. – beroe

1

dplyr библиотека делает его очень легко сделать вещи отдельно для каждого уровня группировки переменной, в вашем случае ID. Мы можем использовать diff, как рекомендует @Richard Scriven, и использовать dplyr::mutate, чтобы добавить новый столбец.

> library(dplyr) 
> df %>% group_by(ID) %>% mutate(new2 = c(diff(I), NA)) 
Source: local data frame [8 x 5] 
Groups: ID 

    ID I Order new new2 
1 1001 5  1 1 1 
2 1001 6  2 -2 -2 
3 1001 4  3 -2 -2 
4 1001 2  4 NA NA 
5 1005 2  1 6 6 
6 1005 8  2 0 0 
7 1005 8  3 -2 -2 
8 1005 6  4 NA NA