Какая польза от чего? - PullRequest
40 голосов
/ 03 августа 2011

Я пытаюсь разобраться с вездесущей функцией which. Пока я не начал читать вопросы / ответы на SO, я никогда не находил в этом необходимости. И я до сих пор не знаю.

Насколько я понимаю, which берет булевский вектор и возвращает слабо более короткий вектор, содержащий индексы элементов, которые были истинными:

> seq(10)
 [1]  1  2  3  4  5  6  7  8  9 10
> x <- seq(10)
> tf <- (x == 6 | x == 8)
> tf
 [1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
> w <- which(tf)
> w
[1] 6 8

Так зачем мне использовать which вместо того, чтобы просто использовать логический вектор напрямую? Я мог видеть некоторые проблемы с памятью с огромными векторами, начиная с length(w) << <code>length(tf), но это вряд ли убедительно. И есть несколько опций в файле справки, которые не очень-то помогают моему пониманию возможного использования этой функции. Примеры в файле справки также не очень помогают.

Редактировать для ясности - Я понимаю, что which возвращает индексы. У меня вопрос о двух вещах: 1) , почему вам когда-нибудь понадобится использовать индексы, а не просто использовать логический вектор выбора? и 2) какое интересное поведение which может сделать предпочтительным использование векторизованного логического сравнения?

Ответы [ 7 ]

25 голосов
/ 03 августа 2011

Хорошо, вот кое-что, что оказалось полезным вчера вечером:

В данном векторе значений каков индекс 3-го значения, отличного от NA?

> x <- c(1,NA,2,NA,3)
> which(!is.na(x))[3]
[1] 5

Немного отличается от использования DWin, хотя я бы сказал, что он тоже неотразим!

19 голосов
/ 03 августа 2011

Название справочной страницы ?which обеспечивает мотивацию. Название:

Какие показатели TRUE?

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

Обычные случаи использования: получение позиции максимального или минимального значения в векторе:

> set.seed(2)
> x <- runif(10)
> which(x == max(x))
[1] 5
> which(x == min(x))
[1] 7

Они были так широко использованы, что были созданы which.max() и which.min():

> which.max(x)
[1] 5
> which.min(x)
[1] 7

Тем не менее, обратите внимание, что определенные формы не являются точными заменами для общей формы. Смотрите ?which.min для деталей. Один пример ниже:

> x <- c(4,1,1)
> which.min(x)
[1] 2
> which(x==min(x))
[1] 2 3
17 голосов
/ 03 августа 2011

Две очень веские причины не забывать which:

1) Когда вы используете «[» для извлечения из фрейма данных, любой расчет в позиции строки, который приводит к NA, вернет ненужную строку. Использование which удаляет NA. Вы можете использовать subset или %in%, которые не создают ту же проблему.

> dfrm <- data.frame( a=sample(c(1:3, NA), 20, replace=TRUE), b=1:20)
> dfrm[dfrm$a >0, ]
      a  b
1     1  1
2     3  2
NA   NA NA
NA.1 NA NA
NA.2 NA NA
6     1  6
NA.3 NA NA
8     3  8
# Snipped  remaining rows

2) Когда вам нужны массивы индикаторов.

12 голосов
/ 03 августа 2011

which может быть полезно (с помощью экономии как компьютерных, так и человеческих ресурсов), например, если вам необходимо отфильтровать элементы фрейма / матрицы данных по заданной переменной / столбцу и обновить другие переменные / столбцы на основе этого,Пример:

df <- mtcars

Вместо:

df$gear[df$hp > 150] <- mean(df$gear[df$hp > 150])

Вы можете сделать:

p <- which(df$hp > 150)
df$gear[p] <- mean(df$gear[p])

Дополнительный случай будет, если вам придется фильтровать фильтрованные элементы, что можетне следует делать с простыми & или |, например, когда вам нужно обновить некоторые части фрейма данных на основе других таблиц данных.Таким образом, требуется хранить (хотя бы временные) индексы отфильтрованного элемента.

Еще одна проблема, которая приходит мне в голову, если вам нужно выполнить цикл как часть фрейма / матрицы данных или сделать этодругие виды преобразований, требующие знания индексов нескольких случаев.Пример:

urban <- which(USArrests$UrbanPop > 80)
> USArrests[urban, ] - USArrests[urban-1, ]
              Murder Assault UrbanPop  Rape
California       0.2      86       41  21.1
Hawaii         -12.1    -165       23  -5.6
Illinois         7.8     129       29   9.8
Massachusetts   -6.9    -151       18 -11.5
Nevada           7.9     150       19  29.5
New Jersey       5.3     102       33   9.3
New York        -0.3     -31       16  -6.0
Rhode Island    -2.9      68       15  -6.6

Извините за фиктивные примеры, я знаю, что не имеет большого смысла сравнивать наиболее урбанизированные штаты США по штатам, предшествующим алфавитным, но я надеюсь, что это имеет смысл :)

Проверка which.min и which.max также дает некоторую подсказку, поскольку вам не нужно много печатать, например:

> row.names(mtcars)[which.max(mtcars$hp)]
[1] "Maserati Bora"
11 голосов
/ 03 августа 2011

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

Однако, если ваш объект представляет собой матрицу, вы можете использовать опцию ,arr.ind, чтобы вернуть результат в виде (строки, столбца) упорядоченных пар:

> x <- matrix(seq(10),ncol=2)
> x
     [,1] [,2]
[1,]    1    6
[2,]    2    7
[3,]    3    8
[4,]    4    9
[5,]    5   10
> which((x == 6 | x == 8),arr.ind=TRUE)
     row col
[1,]   1   2
[2,]   3   2
> which((x == 6 | x == 8))
[1] 6 8

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

7 голосов
/ 05 октября 2011

Удивило, что никто не ответил на это: как насчет эффективности памяти?

Если у вас длинный вектор очень разреженных TRUE, то отслеживание только индексов значений ИСТИНА, вероятно, будетгораздо компактнее.

4 голосов
/ 03 августа 2011

Я часто использую это тихо в исследовании данных.Например, если у меня есть набор данных о детях и я вижу из сводки, что максимальный возраст составляет 23 года (и должен быть 18 лет), я мог бы перейти:

sum(dat$age>18)

Если это было 67 лет, и я хотел посмотретьближе я мог бы использовать:

dat[which(dat$age>18)[1:10], ]

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...