Какая польза от этого?

Я пытаюсь получить представление о вездесущей функции 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) < < length(tf), но это вряд ли убедительно. И в файле справки есть некоторые параметры, которые не добавляют мне многого для понимания возможности использования этой функции. Примеры в файле справки также не очень помогают.

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

Ответ 1

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

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

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

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

Ответ 2

Название man-страницы ?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

Ответ 3

Две очень веские причины не забыть 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) Когда вам нужны индикаторы массива.

Ответ 4

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"

Ответ 5

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

Однако, если ваш объект интереса является матрицей, вы можете использовать параметр ,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

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

Ответ 6

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

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

Ответ 7

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

sum(dat$age>18)

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

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

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