Оператор извлечения `$` () возвращает векторы нулевой длины внутри функции - PullRequest
0 голосов
/ 26 апреля 2018

Я сталкиваюсь с проблемой, когда использую оператор извлечения `$ () внутри функции. Проблема не существует, если я следую той же логике за пределами цикла, поэтому я предполагаю, что может быть проблема с областью видимости, о которой я не знаю.

Общая настройка:

## Make some fake data for your reproducible needs.
set.seed(2345)

my_df <- data.frame(cat_1 = sample(c("a", "b"), 100, replace = TRUE),
                    cat_2 = sample(c("c", "d"), 100, replace = TRUE),
                    continuous  = rnorm(100),
                    stringsAsFactors = FALSE)
head(my_df)

Этот процесс я пытаюсь динамически воспроизвести:

index <- which(`$`(my_df, "cat_1") == "a")

my_df$continuous[index]

Но как только я запрограммировал эту логику в функцию, она перестала работать:

## Function should take a string for the following:
##  cat_var - string with the categorical variable name as it appears in df
##  level - a level of cat_var appearing in df
##  df - data frame to operate on.  Function assumes it has a column 
##    "continuous".
extract_sample <- function(cat_var, level, df = my_df) {

  index <- which(`$`(df, cat_var) == level)

  df$continuous[index]

}

## Does not work.
extract_sample(cat_var = "cat_1", level = "a")

Это возвращается numeric(0). Есть мысли о том, что мне не хватает? Также приветствуются альтернативные подходы.

Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

Проблема заключается в том, как вы индексируете столбец. Это работает, просто слегка подправив вашу:

extract_sample <- function(cat_var, level, df = my_df) {
  index <- df[, cat_var] == level
  df$continuous[index]
}

Использование динамически:

> extract_sample(cat_var = "cat_2", level = "d")
 [1] -0.42769207 -0.75650031  0.64077840 -1.02986889  1.34800344  0.70258431  1.25193247
 [8] -0.62892048  0.48822673  0.10432070  1.11986063 -0.88222370  0.39158408  1.39553002
[15] -0.51464283 -1.05265106  0.58391650  0.10555913  0.16277385 -0.55387829 -1.07822831
[22] -1.23894422 -2.32291394  0.11118881  0.34410388  0.07097271  1.00036812 -2.01981056
[29]  0.63417799 -0.53008375  1.16633422 -0.57130500  0.61614135  1.06768285  0.74182293
[36]  0.56538633  0.16784205 -0.14757303 -0.70928924 -1.91557732  0.61471302 -2.80741967
[43]  0.40552376 -1.88020372 -0.38821089 -0.42043745  1.87370600 -0.46198139  0.10788358
[50] -1.83945868 -0.11052531 -0.38743950  0.68110902 -1.48026285
0 голосов
/ 26 апреля 2018

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

Или, проще, как @ 42 выразил это в первом комментарии в связанном вопросе :

Функция "$" не оценивает свои аргументы, тогда как "[[" делает`.

Вот гораздо более простой набор данных в качестве примера.

my_df <- data.frame(a=c(1,2))
v <- "a"

Сравните обычное использование; первые два дают одинаковый результат, если вы не цитируете его, он анализирует его. Так что третий (сейчас) явно не работает должным образом.

my_df$"a"
## [1] 1 2

my_df$a
## [1] 1 2

my_df$v
## NULL

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

`$`(my_df, "a")
## [1] 1 2

`$`(my_df, v)
## NULL

Вместо этого нам нужно оценить v перед отправкой на $ с помощью do.call.

do.call(`$`, list(my_df, v))
## [1] 1 2

Или, более целесообразно, использовать версию [[, которая сначала оценивает параметры.

`[[`(my_df, v)
## [1] 1 2
0 голосов
/ 26 апреля 2018

Проблема не в функции, а в том, как $ обрабатывает ввод.

cat_var = "cat_1"
length(`$`(my_df,"cat_1"))
#> [1] 100
length(`$`(my_df,cat_var))
#> [1] 0 

Вместо этого вы можете использовать [[ для достижения желаемого результата.

cat_var = "cat_1"
length(`[[`(my_df,"cat_1"))
#> [1] 100
length(`[[`(my_df,cat_var))
#> [1] 100

UPDATE

Было отмечено, что использование [[ таким образом ужасно. И это. Это полезно, когда вы хотите написать что-то вроде lapply(stuff,'[[',1)

Здесь, вероятно, вы должны написать это как my_df[[cat_var]].

Кроме того, этот вопрос / ответ более подробно расскажет о том, почему $ не работает так, как вы этого хотите.

...