Какой самый большой R-gotcha вы столкнулись?



есть ли какой-то R-gotcha, что вы действительно удивили один день? Я думаю, что мы все выиграем от их совместного использования.



вот мой: в индексации списка,my.list[[1]] не my.list[1]. Узнал об этом в первые дни Р.

593   25  

25 ответов:

удаление строк в фрейме данных приведет к добавлению неидеально именованных строк, что затем приведет к ошибкам:

> a<-data.frame(c(1,2,3,4),c(4,3,2,1))
> a<-a[-3,]
> a
  c.1..2..3..4. c.4..3..2..1.
1             1             4
2             2             3
4             4             1
> a[4,1]<-1
> a
Error in data.frame(c.1..2..3..4. = c("1", "2", "4", "1"), c.4..3..2..1. = c(" 4",  : 
  duplicate row.names: 4

Итак, что здесь происходит:

  1. четырехрядные данные.кадр создается, поэтому имена строк c (1,2,3,4)

  2. третья строка удаляется, поэтому имена строк c (1,2,4)

  3. добавляется четвертая строка, и R автоматически устанавливает имя строки равным индексу, т. е. 4, поэтому имена строк-c (1,2,4,4). Это незаконно, потому что имена должны быть уникальны. Я не понимаю, почему этот тип поведения должен быть разрешен Р. Мне кажется, что R должен предоставить уникальное имя строки.

[Хэдли указал на это комментарий.]

при использовании последовательности в качестве индекса для итерации, лучше использовать seq_along() функция, а не что-то вроде 1:length(x).

здесь я создаю вектор и оба подхода возвращают одно и то же:

> x <- 1:10
> 1:length(x)
 [1]  1  2  3  4  5  6  7  8  9 10
> seq_along(x)
 [1]  1  2  3  4  5  6  7  8  9 10

теперь вектор NULL:

> x <- NULL
> seq_along(x) # returns an empty integer; good behavior
integer(0)
> 1:length(x) # wraps around and returns a sequence; this is bad
[1] 1 0

это может вызвать некоторую путаницу в цикле:

> for(i in 1:length(x)) print(i)
[1] 1
[1] 0
> for(i in seq_along(x)) print(i)
>

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

когда что-то неожиданно идет не так в вашем сценарии R, проверьте, что факторы не виноваты.

забывая аргумент drop=FALSE в подмножестве матриц до одного измерения и тем самым отбрасывая класс объектов:

R> X <- matrix(1:4,2)
R> X
     [,1] [,2]
[1,]    1    3
[2,]    2    4
R> class(X)
[1] "matrix"
R> X[,1]
[1] 1 2
R> class(X[,1])
[1] "integer"
R> X[,1, drop=FALSE]
     [,1]
[1,]    1
[2,]    2
R> class(X[,1, drop=FALSE])
[1] "matrix"
R> 
x <- 10.2 * 100
x
1020
as.integer(x)
1019

Я не возражаю, если результат представляется в виде целого числа, когда он действительно может быть представлен в виде целого числа. Например, если значение действительно было 1020, то печать этого для x будет в порядке. Но что-то столь же простое, как 1020.0 в этом случае, когда печать x сделала бы более очевидным, что значение не было целым числом и не представлялось как одно. R должен по умолчанию указывать на какой-либо признак, когда есть чрезвычайно маленький десятичный компонент, который не представлен.

это может быть раздражает, чтобы иметь возможность для комбинаций NA,NaN и Inf. Они ведут себя по-разному, и тесты для одного не обязательно будут работать для других:

> x <- c(NA,NaN,Inf)
> is.na(x)
[1]  TRUE  TRUE FALSE
> is.nan(x)
[1] FALSE  TRUE FALSE
> is.infinite(x)
[1] FALSE FALSE  TRUE

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

> is.finite(x)
[1] FALSE FALSE FALSE

всегда проверяйте, что происходит, когда у вас есть NA!

одна вещь, на которую мне всегда нужно обратить пристальное внимание (после многих болезненных переживаний) - это NA значения. Функции R просты в использовании, но ни в коей мере не будет проблем с вашими данными.

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

> x <- c(1,1,2,NA)
> 1 + NA
[1] NA
> sum(x)
[1] NA
> mean(x)
[1] NA

это экстраполируется в другие функции более высокого уровня.

другими словами, пропущенные значения часто имеют такое же значение, как и измеренные значения по умолчанию. Многие функции имеют na.rm=TRUE/FALSE по умолчанию; стоит потратить некоторое время, решая, как интерпретировать эти параметры по умолчанию.

Edit 1: Марек делает большой смысл. NA значения также могут привести к нежелательным последствиям в индексах. Например:

> TRUE && NA
[1] NA
> FALSE && NA
[1] FALSE
> TRUE || NA
[1] TRUE
> FALSE || NA
[1] NA

это также верно, когда вы пытаетесь создайте условное выражение (для оператора if):

> any(c(TRUE, NA))
[1] TRUE
> any(c(FALSE, NA))
[1] NA
> all(c(TRUE, NA))
[1] NA

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

забывая о том, что strptime() и после POSIXt POSIXlt здесь length() всегда девять -- преобразование в POSIXct помогает:

R> length(strptime("2009-10-07 20:21:22", "%Y-%m-%d %H:%M:%S"))
[1] 9
R> length(as.POSIXct(strptime("2009-10-07 20:21:22", "%Y-%m-%d %H:%M:%S")))
[1] 1
R> 

The round функция всегда округляется до четного числа.

> round(3.5)
[1] 4  

> round(4.5)
[1] 4

математика на целых числах тонко отличается от двойников (а иногда и сложная тоже странная)

обновление они исправили некоторые вещи в R 2.15

1^NA      # 1
1L^NA     # NA
(1+0i)^NA # NA 

0L %/% 0L # 0L  (NA from R 2.15)
0 %/% 0   # NaN
4L %/% 0L # 0L  (NA from R 2.15)
4 %/% 0   # Inf

Я удивлен, что никто не упоминает об этом, но:

T & F можно переопределить, TRUE & FALSE нет.

пример:

x <- sample(c(0,1,NA), 100, T)
T <- 0:10

mean(x, na.rm=T)
# Warning in if (na.rm) x <- x[!is.na(x)] :
#   the condition has length > 1 and only the first element will be used
# Calls: mean -> mean.default
# [1] NA

plot(rnorm(7), axes=T)
# Warning in if (axes) { :
#   the condition has length > 1 and only the first element will be used
# Calls: plot -> plot.default
# Warning in if (frame.plot) localBox(...) :
#   the condition has length > 1 and only the first element will be used
# Calls: plot -> plot.default

[edit]ctrf+F обмануть меня. Шейн упомянул об этом в своем комментарии.

чтение данных может быть более проблематичным, чем вы думаете. Сегодня я обнаружил, что если вы используете читать.csv (), Если линия .csv-файл пуст,читать.csv () автоматически пропускает его. Это имеет смысл для большинства приложений, но если вы автоматически извлекаете данные из (например) строки 27 из нескольких тысяч файлов, а некоторые из предыдущих строк могут быть или не быть пустыми, если вы не будете осторожны, все может пойти ужасно неправильно.

теперь я используйте

data1 <- read.table(file_name, blank.lines.skip = F, sep = ",")

при импорте данных, убедитесь, что вы делаете то, что вы на самом деле думаете, что вы делаете снова и снова и снова...

хитрое поведение .

одна из моих непрерывных ошибок-сравнение набора чисел с плавающей запятой. У меня есть CSV, как:

... mu,  tau, ...
... 0.5, 1.7, ...

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

Да, круто, но all.equal() возвращает TRUE в равных количествах, но текстовое сообщение об ошибке, если это не удается:

> all.equal(1,1)
[1] TRUE
> all.equal(1:10, 1:5)
[1] "Numeric: lengths (10, 5) differ"
> all.equal(1:10, c(1:5,1:5))
[1] "Mean relative difference: 0.625"

решение использует :

if (!isTRUE(all.equal(x, y, tolerance=doubleErrorRate))) {
    ...
}

сколько раз мне приходилось читать all.equals() описание...

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

R> nchar(factor(letters))
 [1] 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

Update: начиная с R 3.2.0 (вероятно, ранее), этот пример теперь генерирует сообщение об ошибке. Как уже упоминалось в комментариях ниже, фактор не является вектором, и nchar() требует вектора.

R> nchar(factor(letters))
Error in nchar(factor(letters)) : 'nchar()' requires a character vector
R> is.vector(factor(letters))
[1] FALSE
  1. случайно перечисляя исходный код функции, забыв включить пустые скобки: например, " ls "против" ls ()"

  2. true & false не вырезайте его как предопределенные константы, как в Matlab, C++, Java, Python; необходимо использовать TRUE & FALSE

  3. невидимые возвращаемые значения: например ".packages () "ничего не возвращает, пока" (.packages ())" возвращает символьный вектор базовых имен пакетов

например, число 3.14 является числовой константой, но выражения +3.14 и -3.14 являются вызовами функций + и -:

> class(quote(3.14))
[1] "numeric"
> class(quote(+3.14))
[1] "call"
> class(quote(-3.14))
[1] "call"

см. раздел 13.2 в книге Джона Чемберса программное обеспечение для анализа данных - Программирование с помощью R

векторы нулевой длины имеют некоторые причуды:

R> kk=vector(mode="numeric",length=0)
R> kk
numeric(0)
R> sum(kk)
[1] 0
R> var(kk)
[1] NA

частичное совпадение в $ оператор: Это относится к спискам, но и по data.frame

df1 <- data.frame(foo=1:10, foobar=10:1)
df2 <- data.frame(foobar=10:1)

df1$foo # Correctly gets the foo column
df2$foo # Expect NULL, but this returns the foobar column!!!

# So, should use double bracket instead:
df1[["foo"]]
df2[["foo"]]

The [[ оператор также имеет exact флаг, но это к счастью TRUE по умолчанию.

частичное совпадение также влияет attr:

x1 <- structure(1, foo=1:10, foobar=10:1)
x2 <- structure(2, foobar=10:1)

attr(x1, "foo") # Correctly gets the foo attribute
attr(x2, "foo") # Expect NULL, but this returns the foobar attribute!!!

# So, should use exact=TRUE
attr(x1, "foo", exact=TRUE)
attr(x2, "foo", exact=TRUE)

работая со списками, есть несколько неинтуитивных вещей:

конечно, разница между [ и [[ требуется некоторое привыкание. Для списков [ возвращает список (потенциально 1) элементов, тогда как [[ возвращает элемент внутри списка.

создания списка:

# When you're used to this:
x <- numeric(5) # A vector of length 5 with zeroes
# ... this might surprise you
x <- list(5)    # A list with a SINGLE element: the value 5
# This is what you have to do instead:
x <- vector('list', 5) # A vector of length 5 with NULLS

Итак, как вставить NULL в список?

x <- list("foo", 1:3, letters, LETTERS) # A sample list
x[[2]] <- 1:5        # Put 1:5 in the second element
# The obvious way doesn't work: 
x[[2]] <- NULL       # This DELETES the second element!
# This doesn't work either: 
x[2] <- NULL       # This DELETES the second element!

# The solution is NOT very intuitive:
x[2] <- list(NULL) # Put NULL in the second element

# Btw, now that we think we know how to delete an element:
x <- 1:10
x[[2]] <- NULL  # Nope, gives an ERROR!
x <- x[-2]    # This is the only way for atomic vectors (works for lists too)

Наконец некоторые продвинутые вещи, такие как индексация через вложенный список:

x <- list(a=1:3, b=list(c=42, d=13, e="HELLO"), f='bar')
x[[c(2,3)]] # HELLO (first selects second element and then it's third element)
x[c(2,3)]   # The second and third elements (b and f)

одна из больших путаниц в R заключается в том, что [i, drop = TRUE] действительно падает уровень фактора, но [i, j, drop = TRUE] не!

> df = data.frame(a = c("europe", "asia", "oceania"), b = c(1, 2, 3))
> df$a[1:2, drop = TRUE]
[1] europe asia  
Levels: asia europe          <---- drops factor levels, works fine
> df[1:2,, drop = TRUE]$a
[1] europe asia  
Levels: asia europe oceania  <---- does not drops factor levels!

подробнее: drop = TRUE не сбрасывает уровни факторов в данных.кадр в то время как в векторе он делает

автоматическое повторение векторы ("обработка"), используемые в качестве индексов:

R> all.numbers <- c(1:5)
R> all.numbers
[1] 1 2 3 4 5
R> good.idxs <- c(T,F,T)
R> #note unfortunate length mismatch
R> good.numbers <- all.numbers[good.idxs]
R> good.numbers
[1] 1 3 4
R> #wtf? 
R> #why would you repeat the vector used as an index 
R> #without even a warning?

исходя из скомпилированного языка и Matlab, я иногда путаюсь в фундаментальном аспекте функций в функциональных языках: они должны быть определена до использовать! Этого недостаточно только для того, чтобы они были проанализированы интерпретатором R. Это в основном поднимает голову, когда вы используете вложенные функции.

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

function f1()
  v1 = 1;
  v2 = f2();
  fprintf('2 == %d\n', v2);

  function r1 = f2()
    r1 = v1 + 1 % nested function scope
  end
end

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

f1 <- function() {
  f2 <- function() {
    v1 + 1
  }

  v1 <- 1

  v2 = f2()

  print(sprintf("2 == %d", v2))
}

мой с сегодняшнего дня: qnorm() принимает вероятности и pnorm () принимает квантили.

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

write.csv(m, file = 'm.csv')
read.csv('m.csv', row.names = 1) # Note the row.names argument

Я написал этот вопрос в SO и был предложен в качестве ответа на этот вопрос @BenBolker.

The apply набор функций работает не только для матриц, но Весы до многомерного массива. В моих исследованиях я часто иметь набор данных, например температуры атмосферы. Это хранится в многомерном массиве с размерами x,y,level,time теперь называется multi_dim_array. Пример макета будет:

multi_dim_array = array(runif(96 * 48 * 6 * 100, -50, 50), 
                        dim = c(96, 48, 6, 100))
> str(multi_dim_array)
#     x     y     lev  time    
 num [1:96, 1:48, 1:6, 1:100] 42.4 16 32.3 49.5 24.9 ...

используя apply можно легко получить:

# temporal mean value
> str(apply(multi_dim_array, 4, mean))
 num [1:100] -0.0113 -0.0329 -0.3424 -0.3595 -0.0801 ...
# temporal mean value per gridcell (x,y location)
> str(apply(multi_dim_array, c(1,2), mean))
 num [1:96, 1:48] -1.506 0.4553 -1.7951 0.0703 0.2915 ...
# temporal mean value per gridcell and level (x,y location, level)
> str(apply(multi_dim_array, c(1,2,3), mean))
 num [1:96, 1:48, 1:6] -3.839 -3.672 0.131 -1.024 -2.143 ...
# Spatial mean per level
> str(apply(multi_dim_array, c(3,4), mean))
 num [1:6, 1:100] -0.4436 -0.3026 -0.3158 0.0902 0.2438 ...

это делает до apply кажется, гораздо меньше счетчик интуитивный. Я сначала, хотя, почему бы не использовать "row" и "col" вместо 1 и 2. Но тот факт, что он также работает для массива с большим количеством измерений, дает понять, почему использование margin как это наиболее предпочтительный вариант.

Comments

    Ничего не найдено.