Удаление нулевых строк из фрейма данных дает фрейм данных с нулевыми строками

У меня есть сценарий с кучей контрольных сумм контроля качества, и он попал в набор данных, в котором не было необходимости удалять какие-либо выборки (строки) из-за контроля качества. Однако этот скрипт дал мне неожиданный результат в виде кадра данных с нулевыми строками. С примерными данными, почему это работает:

data(iris)
##get rid of those pesky factors
iris$Species <- NULL
med <- which(iris[, 1] < 4.9)
medtemp <- iris[-med, ]
dim(medtemp)
[1] 134   4

но это возвращает кадр данных с нулевыми строками:

small <- which(iris[, 1] < 4.0)
smalltemp <- iris[-small, ]
dim(smalltemp)
[1] 0 4

Как и это:

x <- 0
zerotemp <- iris[-x, ]
dim(zerotemp)
[1] 0 4

Кажется, что кадр данных smalltemp должен быть того же размера, что и iris, поскольку вообще нет строк для удаления. Почему это?


person Stedy    schedule 27.05.2011    source источник


Ответы (4)


Дословно скопировано из R Inferno Патрика Бернса, с. 41 (надеюсь, это означает «добросовестное использование» — если кто-то будет возражать, я удалю это)

отрицательное ничто — это что-то

> x2 <- 1:4
> x2[-which(x2 == 3)]
[1] 1 2 4

Приведенная выше команда возвращает все значения в x2, не равные 3.

> x2[-which(x2 == 5)]
numeric(0)

Есть надежда, что приведенная выше команда вернет все x2, поскольку ни один элемент не равен 5. Реальность разрушит эту надежду. Вместо этого он возвращает вектор нулевой длины. Существует тонкая разница между двумя следующими утверждениями:

x[]
x[numeric(0)]

Тонкая разница на входе, но нет тонкости на выходе. Есть по крайней мере три возможных решения исходной задачи.

out <- which(x2 == 5)
if(length(out)) x2[-out] else x2

Другим решением является использование логических индексов:

x2[!(x2 %in% 5)]

Или вы можете, в некотором смысле, работать в обратном направлении:

x2[ setdiff(seq along(x2), which(x2 == 5)) ]
person Ben Bolker    schedule 27.05.2011
comment
Всегда приятно видеть упоминание R Inferno, и этот ответ означает, что сейчас самое время пересмотреть его. - person Stedy; 28.05.2011

Может ли быть так, что во втором примере small оценивается как 0?

Взятие нулевого элемента вектора всегда будет возвращать пустой вектор:

> foo <- 1:3
> foo
[1] 1 2 3
> foo[0]
integer(0)
> 
person lindelof    schedule 27.05.2011

Вместо того, чтобы использовать which для получения ваших индексов, я бы использовал логический вектор и отрицал его. Таким образом, вы можете сделать это:

small <- iris[, 1] < 4.0
smalltemp <- iris[!small, ]
dim(smalltemp)
[1] 150   4

РЕДАКТИРОВАТЬ: я не думаю, что отрицательный индекс 0 (как в вашем случае) разрешен, поскольку нет 0-го индекса, и поэтому R не может исключить этот индекс из вашего выбора. Отрицательное индексирование можно интерпретировать как: «вернуть мне все строки, кроме тех, у которых есть эти индексы».

person diliop    schedule 27.05.2011

Это из-за правил, что делать с нулевым индексом. Допускаются только строго положительные или строго отрицательные индексы. Поскольку [0] ничего не возвращает, а

R> -0 == 0
[1] TRUE

Следовательно, вы ничего не получите там, где ожидали ничего не уронить.

Проблема identical(0) рассматривается как индексирование с помощью NULL, и задокументировано, что это работает так же, как если бы индексирование выполнялось с помощью 0 и, следовательно, такое же поведение.

Это обсуждается в руководстве по определению языка R

person Gavin Simpson    schedule 27.05.2011