Типы данных в R
У каждого значения в R есть один из небольшого набора атомарных типов. Четыре из них делают почти всю работу:
- double — десятичные числа:
3.14,-2,1e6. Именно это R подразумевает под «numeric», и это тип по умолчанию для любого набранного вами числа. - integer — целые числа, хранящиеся точно, записываются с суффиксом
L:42L. - character — текст в кавычках:
"hello". - logical — два значения истинности
TRUEиFALSE(плюсNA, пропущенное значение — см. пропущенные значения).
Есть ещё complex (2 + 3i) для редких задач цифровой обработки сигналов; можно годами обходиться без него. typeof() сообщает, какой тип у значения:
Обратите внимание на первую строку: обычное число — это double, даже если выглядит целым. typeof(42) даёт "double"; целое — только 42L. В повседневном анализе разница почти не важна — R преобразует их молча, — но она объясняет много иначе непонятного вывода typeof().
typeof() против class(): почему они расходятся
В R есть две функции, каждая из которых будто отвечает на вопрос «что это?», но отвечают они на слегка разные вопросы.
typeof()сообщает тип хранения: как значение лежит в памяти.class()сообщает поведенческий тип: ярлык, по которому диспетчеризация методов R решает, какой, скажем,printилиsummaryзапустить.
Для простых значений ответы различаются только словами:
typeof() говорит double (хранение), class() говорит numeric (поведение). Для структур разрыв шире:
Матрица хранится как обычный целочисленный вектор, но ведёт себя как матрица — именно class() заставляет R печатать её сеткой. То же расхождение проявляется у датафреймов (typeof говорит "list", class — "data.frame") и у дат (typeof говорит "double", class — "Date").
Практическое правило: пользуйтесь class(), когда хотите узнать, что это такое в обыденном смысле, и typeof(), когда отлаживаете то, что R делает под капотом.
Проверка типов через is.*()
У каждого типа есть парный предикат, возвращающий TRUE или FALSE, — удобно внутри функций, которым нужно проверить свои входные данные:
Одна ловушка, о которой стоит знать: is.numeric() даёт TRUE и для double, и для integer (это всё числа), а вот is.integer() проверяет хранение, поэтому для обычной 42 он FALSE:
Если вас когда-нибудь удивляло, что is.integer(7) равно FALSE для числа, которое в математическом смысле очевидно целое, — вот почему. 7 — это double; 7L — integer.
Преобразование типов через as.*()
Явное преобразование выполняется семейством as.* — по одной функции на целевой тип:
Два поведения стоит запомнить. as.integer() усекает в сторону нуля, а не округляет — 7.9 становится 7. И когда преобразование бессмысленно, R не бросает ошибку; он возвращает NA и выдаёт предупреждение:
Запустите это — и увидите NA плюс предупреждение «NAs introduced by coercion». Это по-настоящему полезно — преобразуйте целый столбец грязного текста в числа, и неразбираемые записи станут NA вместо падения скрипта, — но это же означает, что тихий NA может просочиться в ваши данные. Когда преобразование важно, проверяйте после него появление новых NA.
Логические значения преобразуются в числа и обратно так, как и хотелось бы: as.numeric(TRUE) это 1, as.logical(0) это FALSE. Поэтому sum() от логического вектора считает количество TRUE:
Неявное приведение: правило одного типа для векторов
Атомарный вектор в R может хранить только один тип. Объедините смешанные значения через c() — и R молча повысит всё до самого гибкого из присутствующих типов по фиксированной лестнице:
logical → integer → double → character
Логические стали 1 и 0, целые стали double, а в последней строке всё стало текстом — character всегда побеждает, потому что любое значение можно записать строкой. Убедиться можно через typeof():
Приведение типов — источник номер один багов «почему мой столбец текстовый?»: одна затесавшаяся строка "N/A" в столбце чисел приводит весь вектор к character. Когда так случилось, сначала исправьте виновное значение, а затем преобразуйте обратно через as.numeric().
Что вы уносите с собой
- Четыре рабочих типа: double («numeric»), integer (
42L), character, logical. typeof()= как хранится;class()= как ведёт себя.3.14— этоdouble, ведущий себя какnumeric.- Проверяйте через
is.numeric()и родственные функции; преобразуйте черезas.numeric()и родственные — неудачные преобразования даютNAс предупреждением, а не ошибку. - Векторы хранят только один тип; смешивание приводит по цепочке logical → integer → double → character.
Дальше: подробнее о числовых типах — округление, математические функции и сюрпризы плавающей точки, общие для всех языков.
Часто задаваемые вопросы
Какие базовые типы данных есть в R?
Атомарные типы — это double (десятичные числа, то, что R называет «numeric»), integer (целые числа с суффиксом L, например 42L), character (текст в кавычках), logical (TRUE/FALSE) и редко используемый complex. Всё более крупное — векторы, датафреймы, списки — строится из них.
В чём разница между typeof() и class() в R?
typeof() сообщает, как значение хранится в памяти (его низкоуровневый тип); class() сообщает, как значение себя ведёт, и это управляет тем, какие методы вызывает R. Для обычного десятичного числа они расходятся в формулировке — typeof(3.14) даёт "double", а class(3.14) даёт "numeric", — а для структур вроде датафреймов typeof() говорит "list", тогда как class() говорит "data.frame".
Как преобразовать типы в R?
Используйте семейство as.*: as.numeric("3.5") даёт 3.5, as.character(42) даёт "42", as.integer(7.9) усекает до 7. Когда преобразование невозможно, R возвращает NA и выдаёт предупреждение, а не ошибку — as.numeric("abc") это NA.
Что такое приведение типов в R?
Когда вы объединяете разные типы в одном векторе, R молча преобразует всё к самому гибкому типу в порядке logical → integer → double → character. Так c(1, 2, "three") становится символьным вектором: "1" "2" "three".