Получение информации об объекте
Классы и типы объектов
Все объекты в R обладают рядом базовых характеристик — класс объекта, который видит и использует пользователь, внутренний класс объекта, который используется в ядре R, и тип хранения объектов в памяти. Классы обычно понимаются как классы S3-/S4-/R6-систем ООП.
Для определения этих характеристик используются следующие функции:
-
class()
определяет класс объекта:
## [1] "character"
# создаём таблицу и смотрим её класс
z <- data.frame(var1 = letters[1:5])
class(z)
## [1] "data.frame"
-
typeof()
определяет внутренние для R типы объектов, например, таблица имеет классdata.frame
, но в ядре R это типlist
и обрабатывается идентично:
typeof(z)
## [1] "list"
-
mode()
илиstorage.mode()
возвращают один из вариантов, с каким типом хранится объект в памяти. Обычно результаты совпадают сtypeof
, но не всегда. Например, массивы — это те же векторы, просто с атрибутом размерности, поэтому и в памяти они хранятся с тем же типом, что и векторы:
## [,1] [,2]
## [1,] "a" "a"
## [2,] "a" "a"
class(mx)
## [1] "matrix" "array"
typeof(mx)
## [1] "character"
mode(mx)
## [1] "character"
-
is.numeric()
,is.character()
,is.logical()
и прочие функции видаis.*
проверяют, является ли объект объектом определённого класса или нет:
is.character('Jane Dow')
## [1] TRUE
is.logical(T)
## [1] TRUE
Измерения и длина объектов
Для большинства часто используемых объектов в R актуально понятие длины или измерения. Под длиной объекта можно понимать количество элементов в объекте — значений в векторе, элементов списка, колонок или строк в таблице и т. д. Основные функции для оценки длин объектов:
-
length()
для оценки количества элементов объекта. Например, количество элементов в векторе или количество элементов в списке. Так как data.frame-таблицы также являются списками, то для таблицlength()
отдаёт количество колонок:
# создаём список, в первом элементе которого вектор латинских букв, во втором — названия месяцев
x <- list(lt = letters,
mnth = month.name)
# определяем длину первого элемента вектора
length(x$lt)
## [1] 26
# определяем количество элементов в векторе
length(x)
## [1] 2
# определяем количество колонок в таблице iris
length(iris)
## [1] 5
-
lengths()
для оценки длин всех элементов списка одновременно:
lengths(x)
## lt mnth
## 26 12
-
nrow()
используется для оценки количества строк в таблице:
nrow(iris)
## [1] 150
ncol(iris)
## [1] 5
Идея измерений больше характерна для массивов, однако может быть применена и к таблицам, результатом будет количество колонок и строк таблицы:
# смотрим первые 6 строк датасета iris
head(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
dim(iris)
## [1] 150 5
Имена элементов и измерений объектов
Для получения и изменения названий элементов объектов — колонок в таблицах, элементов в именованных списках и векторах — используют функцию names()
. Для массивов используется dimnames()
:
# создаём таблицу с колонками col1 и col2, получаем их названия
new_df <- data.frame(col1 = month.name[1:3], col2 = month.abb[1:3])
print(new_df)
## col1 col2
## 1 January Jan
## 2 February Feb
## 3 March Mar
names(new_df)
## [1] "col1" "col2"
# создаём матрицу 2*2
new_mx <- matrix(1:4, nrow = 2, ncol = 2, dimnames = list(c('dim11', 'dim12'), c('dim21', 'dim22')))
print(new_mx)
## dim21 dim22
## dim11 1 3
## dim12 2 4
dimnames(new_mx)
## [[1]]
## [1] "dim11" "dim12"
##
## [[2]]
## [1] "dim21" "dim22"
При работе с таблицами можно также использовать функции colnames()
и rownames()
для получения и изменения названий колонок и строк соответственно. Стоит учесть, что если строкам таблицы не были присвоены названия, то названия всё равно будут в виде вектора значений 1:nrow(dataframe)
, преобразованных в текст:
print(new_df)
## col1 col2
## 1 January Jan
## 2 February Feb
## 3 March Mar
colnames(new_df)
## [1] "col1" "col2"
rownames(new_df)
## [1] "1" "2" "3"
Имена могут быть неуникальными, однако это затрудняет некоторые операции (выделение подвыборки, объединение строк или столбцов), так что подобных ситуаций следует избегать. В некоторых случаях у элементов объектов может не быть имён, например, names(5)
возвращает NULL. Для data.frame
-таблиц запрещены неуникальные названия строк.
Изменение имён в базовом R идёт несколько нехарактерным для большинства объектов R способом: новые значения присваиваются не какому-то объекту, а выражению вида names(x)
. Это возможно, так как для подобных функций определён отдельный метод names<-
, который обновляет вызываемый объект:
# меняем названия колонок на col1, col2 и выводим таблицу
rownames(new_df) <- c('raw1', 'raw2', 'raw3')
print(new_df)
## col1 col2
## raw1 January Jan
## raw2 February Feb
## raw3 March Mar
Атрибуты объектов
Практически все объекты в R имеют метаданные, которые называются атрибутами объекта и организованы в виде именованного списка. Как правило, в атрибутах хранится класс объекта, названия строк и/или столбцов, мерность объекта и прочая полезная информация.
Один из самых распространённых случаев использования атрибутов хорошо знаком всем, кто импортирует SPSS-файлы в R. Так как в SPSS-файлах хранятся как сами значения, так и их метки (например, что 99 означает пропуск данных, а 999 — отказ от ответа), то при импорте в R значения образуют таблицу, а метки оказываются в атрибутах колонок таблицы. Подробнее в Чтение файлов SPSS.
Список атрибутов и их значений можно получить с помощью функции attributes()
либо вызвать значения конкретного атрибута с помощью функции attr()
:
# запрашиваем список атрибутов
attributes(mtcars)
## $names
## [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
## [11] "carb"
##
## $row.names
## [1] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710"
## [4] "Hornet 4 Drive" "Hornet Sportabout" "Valiant"
## [7] "Duster 360" "Merc 240D" "Merc 230"
## [10] "Merc 280" "Merc 280C" "Merc 450SE"
## [13] "Merc 450SL" "Merc 450SLC" "Cadillac Fleetwood"
## [16] "Lincoln Continental" "Chrysler Imperial" "Fiat 128"
## [19] "Honda Civic" "Toyota Corolla" "Toyota Corona"
## [22] "Dodge Challenger" "AMC Javelin" "Camaro Z28"
## [25] "Pontiac Firebird" "Fiat X1-9" "Porsche 914-2"
## [28] "Lotus Europa" "Ford Pantera L" "Ferrari Dino"
## [31] "Maserati Bora" "Volvo 142E"
##
## $class
## [1] "data.frame"
# запрашиваем, какие имена колонок объекта
attr(mtcars, 'names')
## [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
## [11] "carb"
Если у объекта нет атрибутов, то будет возвращен NULL
(как правило, большинство функций R при создании объекта всё же создают и его атрибуты):
# создаём объект и не создаём для него атрибуты
x <- 5
attributes(x)
## NULL
# используем базовую функцию для создания таблицы
x <- data.frame(v1 = 1:5)
attributes(x)
## $names
## [1] "v1"
##
## $class
## [1] "data.frame"
##
## $row.names
## [1] 1 2 3 4 5
При необходимости атрибуты объектов можно создавать самостоятельно. Так как это фактически список дополнительных данных к объекту, то в атрибуты можно записать что угодно. В особо экстремальных случаях в атрибуты можно записать самостоятельные иные объекты, а не просто метаданные основного объекта. При этом значение объекта останется таким же, но в атрибутах будет много других данных:
# создаём простой объект
x <- 'new object'
# создаём атрибут "description", в который записываем описание объекта
attr(x, 'description') <- 'simple text string'
# создаём дополнительный атрибут, в который записываем отдельную таблицу
attr(x, 'additional_table') <- data.frame(var1 = 1:5, var2 = letters[1:5])
# смотрим атрибуты объекта
attributes(x)
## $description
## [1] "simple text string"
##
## $additional_table
## var1 var2
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
## 5 5 e
Аналогичным образом можно извлечь объекты, которые хранятся в атрибутах другого объекта:
## 'data.frame': 5 obs. of 2 variables:
## $ var1: int 1 2 3 4 5
## $ var2: chr "a" "b" "c" "d" ...
Структура объектов
Нередко при работе с разными объектами необходимо получить сводную информацию об объекте — класс объекта, иерархию его элементов, первые значения каждого элемента и т. д. Для этих целей используется функция str()
(от structure
), которая выводит каждый элемент объекта в виде вектора значений. Например, при просмотре структуры таблицы iris
мы получаем класс объекта (data.frame
), количество строк и столбцов, название колонок, тип элементов и первые десять значений каждой колонки:
str(iris)
## 'data.frame': 150 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
При просмотре структуры списка, который в качестве одного из элементов содержит другой список, точно так же отображается каждый элемент списка, его тип, в том числе и типы и элементы вложенного списка. Вложенный список дополнительно выделен точками и отступом:
## List of 3
## $ e1: int [1:5] 1 2 3 4 5
## $ e2: chr [1:5] "a" "b" "c" "d" ...
## $ e3:List of 2
## ..$ e31: num [1:5] 0.488 -0.629 0.559 0.687 -0.435
## ..$ e32: num [1:5] 0.817 0.961 0.785 0.48 0.825