Utwórz plik data.frame, w którym kolumna jest listą

80

Wiem, jak dodać kolumnę listy:

> df <- data.frame(a=1:3)
> df$b <- list(1:1, 1:2, 1:3)
> df
  a       b
1 1       1
2 2    1, 2
3 3 1, 2, 3

To działa, ale nie:

> df <- data.frame(a=1:3, b=list(1:1, 1:2, 1:3))
Error in data.frame(1L, 1:2, 1:3, check.names = FALSE, stringsAsFactors = TRUE) : 
  arguments imply differing number of rows: 1, 2, 3

Czemu?

Czy istnieje sposób na utworzenie df(powyżej) w jednym wywołaniu data.frame?

flodel
źródło

Odpowiedzi:

103

Nieco niejasno, z ?data.frame:

Jeśli lista lub ramka danych lub macierz są przekazywane do 'data.frame', to tak jakby każdy komponent lub kolumna zostały przekazane jako oddzielny argument (z wyjątkiem macierzy klasy '"model.matrix"' i tych chronionych przez 'I ' ).

(podkreślenie dodane).

Więc

data.frame(a=1:3,b=I(list(1,1:2,1:3)))

wydaje się działać.

Ben Bolker
źródło
17
Dla zainteresowanych „ja” oznacza „powstrzymanie interpretacji / konwersji obiektów”. Tworzy identyczny obiekt, ale z dopiskiem „AsIs” do zestawu klas. Klasa „AsIs” jest tak naprawdę po to, by ją odczytać funkcje data.frame () i formula (). Dowiedz się więcej tutaj .
pwilcox
2
niesamowite, dzięki za rozwiązanie. choć tylko Idla Inhibit Interperetation / Conversion of objects wydaje się trochę za krótkie :)
sertsedat
@pwilcox bardzo interesujące. Czy istnieje metoda wywołania obiektu, aby sprawdzić, czy jest on chroniony przeze mnie? Chyba tak class()? np. I(iris) -> i; i %>% class() 3 [1] "AsIs" "data.frame"(zwraca klasę AsIs)
stevec
33

Jeśli pracujesz z data.tables, możesz uniknąć połączenia zI()

library(data.table)
# the following works as intended
data.table(a=1:3,b=list(1,1:2,1:3))

   a     b
1: 1     1
2: 2   1,2
3: 3 1,2,3
mnel
źródło
Jest to niedoceniana cecha z data.tableszerokim marginesem
data księżniczka
22

data_frames (różnie nazywane tibbles, tbl_df, tbl) natywnie wspierać tworzenie lista kolumn przy użyciu data_framekonstruktora. Aby z nich skorzystać, załaduj jedną z wielu bibliotek, takich jak tibble, dplyrlub tidyverse.

> data_frame(abc = letters[1:3], lst = list(1:3, 1:3, 1:3))
# A tibble: 3 × 2
    abc       lst
  <chr>    <list>
1     a <int [3]>
2     b <int [3]>
3     c <int [3]>

Właściwie są data.framespod maską, ale nieco zmodyfikowane. Prawie zawsze można ich normalnie używać data.frames. Jedynym wyjątkiem, jaki znalazłem, jest to, że kiedy ludzie wykonują niewłaściwe kontrole klas, powodują problemy:

> #no problem
> data.frame(x = 1:3, y = 1:3) %>% class
[1] "data.frame"
> data.frame(x = 1:3, y = 1:3) %>% class == "data.frame"
[1] TRUE
> #uh oh
> data_frame(x = 1:3, y = 1:3) %>% class
[1] "tbl_df"     "tbl"        "data.frame"
> data_frame(x = 1:3, y = 1:3) %>% class == "data.frame"
[1] FALSE FALSE  TRUE
> #dont use if with improper testing!
> if(data_frame(x = 1:3, y = 1:3) %>% class == "data.frame") "something"
Warning message:
In if (data_frame(x = 1:3, y = 1:3) %>% class == "data.frame") "something" :
  the condition has length > 1 and only the first element will be used
> #proper
> data_frame(x = 1:3, y = 1:3) %>% inherits("data.frame")
[1] TRUE

Polecam przeczytanie o nich w R 4 Data Science (bezpłatnie).

CoderGuy123
źródło
1
R się porusza i rośnie i myślę, że to jest odpowiedź na pytanie z 2018 roku i jakoś należy ją jako taką oznaczyć.
Fitzroy Hogsflesh
Jeśli będzie wystarczająco popularny, osiągnie szczyt. Wielu z nas nadal używa podstawowego R ...
Ben Bolker