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Итак, что здесь происходит:
четырехрядные данные.кадр создается, поэтому имена строк c (1,2,3,4)
третья строка удаляется, поэтому имена строк c (1,2,4)
добавляется четвертая строка, и 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>
математика на целых числах тонко отличается от двойников (а иногда и сложная тоже странная)
обновление они исправили некоторые вещи в 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 2Update: начиная с 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
случайно перечисляя исходный код функции, забыв включить пустые скобки: например, " ls "против" ls ()"
true & false не вырезайте его как предопределенные константы, как в Matlab, C++, Java, Python; необходимо использовать TRUE & FALSE
невидимые возвращаемые значения: например ".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.framedf1 <- 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)) }
для меня это просто способ, в котором при экспорте данных.кадр в текстовый файл с помощью
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