"Встроенный" data.frame в R. Что это такое, как он называется, почему он ведет себя так, как он себя ведет?

У меня есть следующая структура данных в R:

df <- structure(
  list(
    ID = c(1L, 2L, 3L, 4L, 5L),
    var1 = c('a', 'b', 'c', 'd', 'e'),
    var2 = structure(
      list(
        var2a = c('v', 'w', 'x', 'y', 'z'),
        var2b = c('vv', 'ww', 'xx', 'yy', 'zz')),
      .Names = c('var2a', 'var2b'),
      row.names = c(NA, 5L),
      class = 'data.frame'),
    var3 = c('aa', 'bb', 'cc', 'dd', 'ee')),
  .Names = c('ID', 'var1', 'var2', 'var3'),
  row.names = c(NA, 5L),
  class = 'data.frame')

# Looks like this:
#   ID var1 var2.var2a var2.var2b var3
# 1  1    a          v         vv   aa
# 2  2    b          w         ww   bb
# 3  3    c          x         xx   cc
# 4  4    d          y         yy   dd
# 5  5    e          z         zz   ee

Это выглядит как нормальный фрейм данных, и он ведет себя как таковой большей частью; но см. length и class свойства следующих столбцов:

class(df)
# [1] "data.frame"

df[1,]
# ID var1 var2.var2a var2.var2b var3
# 1     a          v         vv   aa

dim(df)
# [1] 5 4
# One less than expected due to embedded data frame

lapply(df, class)
# $ID
# [1] "integer"
# 
# $var1
# [1] "character"
# 
# $var2
# [1] "data.frame"
# 
# $var3
# [1] "character"

lapply(df, length)
# $ID
# [1] 5
#
# $var1
# [1] 5
#
# $var2
# [1] 2
#
# $var3
# [1] 5
# str(df)

# 'data.frame': 5 obs. of  4 variables:
#   $ ID  : int  1 2 3 4 5
# $ var1: chr  "a" "b" "c" "d" ...
# $ var2:'data.frame':  5 obs. of  2 variables:
#   ..$ var2a: chr  "v" "w" "x" "y" ...
# ..$ var2b: chr  "vv" "ww" "xx" "yy" ...
# $ var3: chr  "aa" "bb" "cc" "dd" ...

Мои вопросы:

1) Что это?

Я никогда раньше не сталкивался с этим. Это обычный формат для некоторых из вас? Каковы потенциальные варианты использования?

2) Что называется?

Я назвал это "встроенным" из-за отсутствия лучшего слова. Кто-то предложил "вложенные", но я не думаю, что это правильно, см. Отдельный раздел с tidyverse tibble ниже.

3) Почему это разрешено?

Я бы ожидал, что команда structure выше завершится неудачей, потому что я, хотя эти data.frames - это по существу списки, где каждый элемент (столбец) имеет одинаковое количество элементов (строк). Это правило кажется нарушенным в этом примере, поскольку var2 имеет length = 2 (количество столбцов!). Тем не менее, подмножество df на удивление преуспевает обычным способом:

df[3,]
#   ID var1 var2.var2a var2.var2b var3
# 3  3    c          x         xx   cc

Что происходит?


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

library(tidyverse)
df <- data_frame(
  x = c(1L, 2L, 3L),
  nested = list(data_frame(x = c('a', 'b', 'c')), 
                data_frame(x = c('a', 'b', 'c')), 
                data_frame(x = c('d', 'e', 'f'))))
unnest(df)
# # A tibble: 9 × 2
#       x     x
#   <int> <chr>
# 1     1     a
# 2     1     b
# 3     1     c
# 4     2     a
# 5     2     b
# 6     2     c
# 7     3     d
# 8     3     e
# 9     3     f

Ответ 1

Я думаю, что strucutre делает это довольно ясно.

str(df)
# 'data.frame':   5 obs. of  4 variables:
#  $ ID  : int  1 2 3 4 5
#  $ var1: chr  "a" "b" "c" "d" ...
#  $ var2:'data.frame':   5 obs. of  2 variables:
#   ..$ var2a: chr  "v" "w" "x" "y" ...
#   ..$ var2b: chr  "vv" "ww" "xx" "yy" ...
#  $ var3: chr  "aa" "bb" "cc" "dd" ...

Это data.frame с столбцом (var2), который содержит data.frame. Это не очень легко создать, поэтому я не совсем уверен, как вы это сделали, но это не технически "незаконно" в R.

data.frames могут содержать матрицы и другие data.frames. Поэтому он не просто смотрит на length() элементов, он смотрит на dim() элементов, чтобы увидеть, имеет ли он правильное количество "строк".

Я часто "исправляю" или расширяю эти data.frames с помощью

fixed <- do.call("data.frame", df)