2016-08-03 1 views
8

Не уверен, что если я назвал вопрос правильно, потому что я не в полной мере понять причину следующего поведения:R - образец используется в% в% изменения dataframe, которые в настоящее время subsetted

dfSet <- data.frame(ID = sample(1:15, size = 15, replace = FALSE), va1 = NA, va3 = 0, stringsAsFactors = FALSE) 

dfSet[1:10, ]$va1 <- 'o1' 
dfSet[11:15, ]$va1 <- 'o2' 

dfSet[dfSet$ID %in% sample(dfSet[dfSet$va1 == 'o1', ]$ID, 7, replace = FALSE), ]$va3 <- 1 

print(length(unique(dfSet$ID))) 

Я ожидаю, что окончательная печать показывает 15, но это не так. Вместо этого появляется 13 или 14, и dfSet изменен таким образом, что есть как минимум две строки с одинаковым идентификатором. Похоже, что эта часть кода:

dfSet[dfSet$ID %in% sample(dfSet[dfSet$va1 == 'o1', ]$ID, 7, replace = FALSE), ]$va3 <- 1 

изменить столбец $ ID - я не знаю почему?

Обход:

temp <- sample(dfSet[dfSet$va1 == 'o1', ]$ID, 7, replace = FALSE) 
dfSet[dfSet$ID %in% temp, ]$va3 <- 1 

В этом случае все работает, как ожидалось - есть 15 строк с уникальным идентификатором.

Вопрос в том, почему прямое использование образца в% in% изменяет структуру данных?

+1

Другим «работающим» будет «dfSet [dfSet $ ​​ID% in% sample (dfSet [dfSet $ ​​va1 == 'o1',] $ ID, 7, replace = FALSE)," va3 "] <- 1 '. Проблема, по-видимому, связана с оценкой как '[<-', так и' $ <- ', хотя я беспокоюсь о том, чтобы сделать ясный пример для ответа. – MrFlick

+0

Я уверен, что ваша «работа вокруг» будет работать в каждом случае? Или, может быть, я должен знать о sth? Я собираюсь использовать ваше решение в массовом порядке (так как это однострочный), поэтому я хотел бы быть уверенным, что все в порядке. –

+0

Да. Просто не комбинируйте '[]' и '$' с '<-', просто используйте один или другой с фреймом данных, и вы будете в безопасности. – MrFlick

ответ

7

Что, кажется, проблема заключается в том, что R делает некоторые хитрая вещь, когда вы назначаете функционировать возвращаемые значения. Например, что-то вроде

a <- c(1,3) 
names(a) <- c("one", "three") 

будет выглядеть очень странно на большинстве языков. Как назначить значение возвращаемому значению функции? Что действительно происходит, так это то, что определена функция с именем names<-. В основном это возвращает преобразованную версию исходного объекта, которая затем может использоваться для замены значения, переданного этой функции.Так что это действительно выглядит как этот

.temp. <- `names<-`(a, c("one","three")) 
a <- .temp. 

переменной a всегда полностью заменить, а не только его название.

Когда вы делаете что-то вроде

dfSet$a<-1 

, что на самом деле происходит снова

.temp. <- "$<-"(dfSet, a, 1) 
dfSet <- .temp. 

Теперь все становится немного сложнее, когда вы пытаетесь сделать как [] и $ Подменю. Посмотрите на этот образец

#for subsetting 
f <- function(x,v) {print("testing"); x==v} 
x <- rep(0:1, length.out=nrow(dfSet)) 
dfSet$a <- 0 

dfSet[f(x,1),]$a<-1 

Обратите внимание, что «тестирование» печатается дважды. Что происходит на самом деле больше похож

.temp1. <- "$<-"(dfSet[f(x,1),], a, 1) 
.temp2. <- "[<-"(dfSet, f(x,1), , .temp1.) 
dfSet <- .temp2. 

Так f(x,1) вычисляется дважды. Это означает, что sample будет оцениваться дважды.

Ошибка немного более очевидным является то, вы пытаетесь заменить переменную, которая не существует еще

dfSet[f(x,1),]$b<-1 
# Warning message: 
# In `[<-.data.frame`(`*tmp*`, f(x, 1), , value = list(ID = c(6L, : 
# provided 4 variables to replace 3 variables 

Здесь вы получите предупреждение, потому что .temp1. переменная, как добавляется столбец и теперь имеет 4 колонки, но когда вы пытаетесь выполнить присвоение .temp2., теперь у вас есть проблема, что фрагмент кадра данных, который вы пытаетесь заменить, отличается от другого.

Идентификаторы заменяются, потому что оператор $<- не просто возвращает новый столбец, он возвращает новый data.frame с обновленным столбцом до любого назначенного вами значения. Это означает, что строки, которые были обновлены, возвращаются вместе с идентификатором, который был там, когда произошло присвоение. Это сохраняется в переменной .temp1.. Затем, когда вы выполняете назначение [<-, вы выбираете новый набор строк для замены. Значения всех столбцов этих строк заменяются значениями от .temp1.. Это означает, что вы будете переписывать идентификаторы для замещающих строк, и они могут отличаться, поэтому вы, вероятно, закончите с двумя или более копиями данного идентификатора.

+0

Можете ли вы объяснить, почему Столбец 'ID' в этом примере перезаписывается? –

+0

@C_Z_ Я попытался добавить абзац для конкретного вопроса. – MrFlick

+0

' trace (f) 'показывает две оценки, равно как и' trace (sample) '. Это помогает показать, что образец действительно оценивается дважды. –

2

Хотя я не уверен на 100%, я подозреваю, что R работает sample два раза. Если подмножество и назначить в R, например:

x[i:j,]$v1 <- 1 

Он получает оценку, как «вынимает строки I в J из й в качестве временного кадра данных, присвоить 1 к колонке v1 этого кадр данных, а затем скопировать временный кадр данных обратно в строки i-j в x ".

Так что, возможно, индексирующее выражение (i: j) выполняется дважды (один раз для извлечения и один раз для возврата), и если это случайная переменная, он будет возвращать результаты в разные строки, чем исходные выбран.

+0

Я считаю, что выражение подмножества оценивается дважды, но только, как отмечает М. Флик, потому что вызываются как '' $ <-. Data.frame "и' [<-. Data.frame "' (в этом порядке). Во-первых, не сохраненный объект ('x [i: j,]') передается в '' $ <- "', а его столбцу "v1" присваивается значение "1", а затем этот измененный не сохраненный " data.frame "_a целое_ передается' '[<-" 'и назначается' x [i: j,] ', поэтому' i: j' оценивается дважды как аргумент подмножества. –

1

Рассмотрим простой пример:

x <- data.frame(a=1:10, b=10:1) 
x$b <- 5 

Что вторая линия на самом деле делает это

x <- `$<-`(x, 'b', 5) 

Вы можете видеть, что $<- это просто функция, которая принимает три аргумента, объект, имя и значение. (Обратите внимание на обратных кавычках необходимы, если вы хотите использовать $<- непосредственно.)

Проблемы я думаю, что в вашем примере x этом выражение, которое оценивает разные вещи каждый раз, когда он оцененный, в связи с вызовом sample , поэтому вам следует избегать этого.

Альтернативой является использование [<-, который, по-видимому, не имеют этой проблемы:

dfSet[dfSet$ID %in% sample(dfSet[dfSet$va1 == 'o1', ]$ID, 7, replace = FALSE), 'va3'] <- 1 
Смежные вопросы