# Обработка данных — краткий справочник > Неочевидное поведение, подводные камни и непростые значения по умолчанию функций R. > Только то, чего Claude ещё не знает. --- ## Extract / Extract.data.frame Подводные камни индексации в базовом R. - `m[j = 2, i = 1]` — это `m[2, 1]`, а не `m[1, 2]`: имена аргументов **игнорируются** в `[`, сопоставление только позиционное. Никогда не именуйте аргументы индексов. - Индексация фактором: `x[f]` использует целочисленные коды фактора `f`, а не его символьные метки. Используйте `x[as.character(f)]` для индексации по меткам. - `x[[]]` без индекса всегда вызывает ошибку. `x$name` по умолчанию выполняет частичное сопоставление; `x[["name"]]` — нет (по умолчанию точное). - Присваивание `NULL` через `x[[i]] <- NULL` или `x$name <- NULL` **удаляет** этот элемент списка. - `[` для фрейма данных с одним столбцом: `df[, 1]` возвращает **вектор** (по умолчанию drop=TRUE для столбцов), но `df[1, ]` возвращает **фрейм данных** (drop=FALSE для строк). Явно задавайте `drop = FALSE`. - Индексация фрейма данных матрицей (`df[cbind(i,j)]`) сначала преобразует его в матрицу — избегайте этого. --- ## subset Используйте только интерактивно; небезопасна для программирования. - Аргумент `subset` использует **нестандартное вычисление** — имена столбцов разрешаются во фрейме данных, что при программном использовании может незаметно подхватить не те переменные. В функциях используйте `[` с явной логикой. - `NA` в логическом условии трактуются как `FALSE` (строки незаметно отбрасываются). - После выбора подмножества факторы могут сохранять неиспользуемые уровни; вызывайте `droplevels()`. --- ## match / %in% - `%in%` **никогда не возвращает NA** — поэтому, в отличие от `==`, безопасен для условий `if()`. - `match()` возвращает только позицию **первого** совпадения; повторы в `table` игнорируются. - Факторы, векторы raw и списки перед сопоставлением преобразуются в символьный вид. - `NaN` совпадает с `NaN`, но не с `NA`; `NA` совпадает только с `NA`. --- ## apply - Для **фрейма данных** `apply` сначала выполняет преобразование в матрицу через `as.matrix` — смешанные типы становятся символьными. - Ориентация возвращаемого значения транспонирована: если FUN возвращает вектор длины n, размерность результата — `c(n, dim(X)[MARGIN])`. Результаты для строк становятся **столбцами**. - Результаты-факторы в выходном массиве преобразуются в символьные значения. - Имена аргументов `...` не должны совпадать с `X`, `MARGIN` или `FUN` (риск частичного сопоставления). --- ## lapply / sapply / vapply - `sapply` может непредсказуемо вернуть вектор, матрицу или список — в неинтерактивном коде используйте `vapply` с явным шаблоном `FUN.VALUE`. - Прямой вызов примитивов в `lapply` может вызвать проблемы диспетчеризации; оборачивайте в `function(x) is.numeric(x)`, а не передавайте просто `is.numeric`. - `sapply` с `simplify = "array"` может создавать массивы большей размерности (не только матрицы). --- ## tapply - Возвращает **массив** (не фрейм данных). Информация о классе возвращаемых значений **отбрасывается** (например, объекты Date становятся числовыми). - Аргументы `...` для FUN **не** разделяются по ячейкам — они применяются глобально, поэтому FUN не должна ожидать дополнительные аргументы той же длины, что и X. - `default = NA` заполняет пустые ячейки; задавайте `default = 0` для операций наподобие суммирования. До R 3.4.0 значение было жёстко задано как `NA`. - Используйте `array2DF()` для преобразования результата во фрейм данных. --- ## mapply - Имя аргумента — `SIMPLIFY` (все буквы заглавные), а не `simplify` — несогласованность с `sapply`. - `MoreArgs` должен быть **списком** аргументов, по которым не выполняется векторизация. - Повторяет более короткие аргументы до общей длины; аргумент нулевой длины даёт результат нулевой длины. --- ## merge - По умолчанию `by` равен `intersect(names(x), names(y))` — объединение может незаметно выполняться по непредусмотренным столбцам, если во фреймах данных совпадают имена столбцов. - `by = 0` или `by = "row.names"` объединяет по именам строк, добавляя столбец "Row.names". - `by = NULL` (или оба `by.x`/`by.y` длины 0) создаёт **декартово произведение**. - Результат по умолчанию сортируется по столбцам `by` (`sort = TRUE`). Для несортированного вывода используйте `sort = FALSE`. - Совпадения повторяющихся ключей создают **все комбинации** (одна строка на каждую пару совпадений). --- ## split - Если `f` — список факторов, используется их взаимодействие; уровни, содержащие `"."`, могут привести к неожиданным разбиениям, если не изменить `sep`. - `drop = FALSE` (по умолчанию) сохраняет пустые уровни факторов как пустые элементы списка. - Поддерживает синтаксис формул: `split(df, ~ Month)`. --- ## cbind / rbind - `cbind` для фреймов данных вызывает `data.frame(...)`, а не `cbind.matrix`. Смешивание матриц и фреймов данных может дать неожиданные результаты. - `rbind` для фреймов данных сопоставляет столбцы **по имени**, а не по позиции. Отсутствующие столбцы получают `NA`. - `cbind(NULL)` возвращает `NULL` (не матрицу). Для согласованности `rbind(NULL)` также возвращает `NULL`. --- ## table - По умолчанию **исключает NA** (`useNA = "no"`). Используйте `useNA = "ifany"` или `exclude = NULL`, чтобы подсчитывать NA. - Непустое и не стандартное значение `exclude` подразумевает `useNA = "ifany"`. - Результат всегда является **массивом** (даже одномерным), класса "table". Преобразуйте во фрейм данных через `as.data.frame(tbl)`. - Два вида NA (NA как уровень фактора и фактический NA) обрабатываются по-разному в зависимости от `useNA`/`exclude`. --- ## duplicated / unique - `duplicated` помечает **второе и последующие** вхождения как TRUE, не первое. Используйте `fromLast = TRUE` для обратного порядка. - Для фреймов данных работает с целыми строками. Для списков выполняет рекурсивное сравнение. - `unique` сохраняет **первое** вхождение каждого значения. --- ## data.frame (подводные камни) - `stringsAsFactors = FALSE` — значение по умолчанию начиная с R 4.0.0 (раньше было TRUE). - Атомарные векторы повторяются до длины самого длинного столбца, но только при точной кратности. Защитите их с помощью `I()`, чтобы предотвратить преобразование. - Повторяющиеся имена столбцов допускаются только с `check.names = FALSE`, но многие операции незаметно устраняют повторы имён. - Аргументы-матрицы разворачиваются в несколько столбцов, если не защищены `I()`. --- ## factor (подводные камни) - `as.numeric(f)` возвращает **целочисленные коды**, а не исходные значения. Используйте `as.numeric(levels(f))[f]` или `as.numeric(as.character(f))`. - Между факторами работают только `==` и `!=`; у факторов должны быть одинаковые наборы уровней. Упорядоченные факторы поддерживают `<`, `>`. - `c()` для факторов объединяет наборы уровней (начиная с R 4.1.0), но более ранние версии преобразовывали их в целые числа. - Уровни по умолчанию сортируются, но порядок сортировки **зависит от локали** на момент создания. --- ## aggregate - Интерфейс формул (`aggregate(y ~ x, data, FUN)`) по умолчанию отбрасывает группы `NA`. - Метод для фрейма данных требует, чтобы `by` был **списком** (не вектором). - Возвращает столбцы, названные по группирующим переменным, а столбец результата сохраняет исходное имя. - Если FUN возвращает несколько значений, столбец результата является **столбцом-матрицей** внутри фрейма данных. --- ## complete.cases - Возвращает логический вектор: TRUE для строк, в которых **нет** NA во всех столбцах/аргументах. - Работает с несколькими аргументами (например, `complete.cases(x, y)` проверяет оба). --- ## order - Возвращает **вектор перестановки** индексов, а не отсортированные значения. Используйте `x[order(x)]` для сортировки. - По умолчанию сортирует по возрастанию; используйте `-x` для числовой сортировки по убыванию или `decreasing = TRUE`. - Сортировка символов зависит от локали. Используйте `method = "radix"` для быстрой сортировки, не зависящей от локали. - `sort.int()` с `method = "radix"` значительно быстрее для больших целочисленных/символьных векторов.