2016-04-02 2 views
1

Возможно, это только я, но я всегда находил str неудовлетворительным. Он часто слишком многословный, но не очень информативный во многих случаях.альтернатива `str()` в R

Я на самом деле очень нравится описание функции (?str):

Компактно отобразить внутреннюю структуру R объекта

и этот бит в частности

В идеале , отображается только одна строка для каждой «базовой» структуры.

Только это, во многих случаях, реализация по умолчанию str просто не оправдывает такого описания.

Хорошо, допустим, это работает частично хорошо для data.frame s.

library(ggplot2) 
str(mpg) 

> str(mpg) 
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 234 obs. of 11 variables: 
$ manufacturer: chr "audi" "audi" "audi" "audi" ... 
$ model  : chr "a4" "a4" "a4" "a4" ... 
$ displ  : num 1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ... 
$ year  : int 1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ... 
$ cyl   : int 4 4 4 4 6 6 6 4 4 4 ... 
$ trans  : chr "auto(l5)" "manual(m5)" "manual(m6)" "auto(av)" ... 
$ drv   : chr "f" "f" "f" "f" ... 
$ cty   : int 18 21 20 21 16 18 18 18 16 20 ... 
$ hwy   : int 29 29 31 30 26 26 27 26 25 28 ... 
$ fl   : chr "p" "p" "p" "p" ... 
$ class  : chr "compact" "compact" "compact" "compact" ... 

Тем не менее, для data.frame это не так информативно, как хотелось бы. В дополнение к классу было бы очень полезно, чтобы он показывал число значений NA и число уникальных значений, например.

Но для других объектов он быстро становится неуправляемым. Например:

gp <- ggplot(mpg, aes(x = displ, y = hwy)) + 
    geom_point() 
str(gp) 

> str(gp) 
List of 9 
$ data  :Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 234 obs. of 11 variables: 
    ..$ manufacturer: chr [1:234] "audi" "audi" "audi" "audi" ... 
    ..$ model  : chr [1:234] "a4" "a4" "a4" "a4" ... 
    ..$ displ  : num [1:234] 1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ... 
    ..$ year  : int [1:234] 1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ... 
    ..$ cyl   : int [1:234] 4 4 4 4 6 6 6 4 4 4 ... 
    ..$ trans  : chr [1:234] "auto(l5)" "manual(m5)" "manual(m6)" "auto(av)" ... 
    ..$ drv   : chr [1:234] "f" "f" "f" "f" ... 
    ..$ cty   : int [1:234] 18 21 20 21 16 18 18 18 16 20 ... 
    ..$ hwy   : int [1:234] 29 29 31 30 26 26 27 26 25 28 ... 
    ..$ fl   : chr [1:234] "p" "p" "p" "p" ... 
    ..$ class  : chr [1:234] "compact" "compact" "compact" "compact" ... 
$ layers  :List of 1 
    ..$ :Classes 'LayerInstance', 'Layer', 'ggproto' <ggproto object: Class LayerInstance, Layer> 
    aes_params: list 
    compute_aesthetics: function 
    compute_geom_1: function 
    compute_geom_2: function 
    compute_position: function 
    compute_statistic: function 
    data: waiver 
    draw_geom: function 
    geom: <ggproto object: Class GeomPoint, Geom> 
     aesthetics: function 
     default_aes: uneval 
     draw_group: function 
     draw_key: function 
     draw_layer: function 
     draw_panel: function 
     extra_params: na.rm 
     handle_na: function 
     non_missing_aes: size shape 
     parameters: function 
     required_aes: x y 
     setup_data: function 
     use_defaults: function 
     super: <ggproto object: Class Geom> 
    geom_params: list 
    inherit.aes: TRUE 
    layer_data: function 
    map_statistic: function 
    mapping: NULL 
    position: <ggproto object: Class PositionIdentity, Position> 
     compute_layer: function 
     compute_panel: function 
     required_aes: 
     setup_data: function 
     setup_params: function 
     super: <ggproto object: Class Position> 
    print: function 
    show.legend: NA 
    stat: <ggproto object: Class StatIdentity, Stat> 
     compute_group: function 
     compute_layer: function 
     compute_panel: function 
     default_aes: uneval 
     extra_params: na.rm 
     non_missing_aes: 
     parameters: function 
     required_aes: 
     retransform: TRUE 
     setup_data: function 
     setup_params: function 
     super: <ggproto object: Class Stat> 
    stat_params: list 
    subset: NULL 
    super: <ggproto object: Class Layer> 
$ scales  :Classes 'ScalesList', 'ggproto' <ggproto object: Class ScalesList> 
    add: function 
    clone: function 
    find: function 
    get_scales: function 
    has_scale: function 
    input: function 
    n: function 
    non_position_scales: function 
    scales: list 
    super: <ggproto object: Class ScalesList> 
$ mapping :List of 2 
    ..$ x: symbol displ 
    ..$ y: symbol hwy 
$ theme  : list() 
$ coordinates:Classes 'CoordCartesian', 'Coord', 'ggproto' <ggproto object: Class CoordCartesian, Coord> 
    aspect: function 
    distance: function 
    expand: TRUE 
    is_linear: function 
    labels: function 
    limits: list 
    range: function 
    render_axis_h: function 
    render_axis_v: function 
    render_bg: function 
    render_fg: function 
    train: function 
    transform: function 
    super: <ggproto object: Class CoordCartesian, Coord> 
$ facet  :List of 1 
    ..$ shrink: logi TRUE 
    ..- attr(*, "class")= chr [1:2] "null" "facet" 
$ plot_env :<environment: R_GlobalEnv> 
$ labels  :List of 2 
    ..$ x: chr "displ" 
    ..$ y: chr "hwy" 
- attr(*, "class")= chr [1:2] "gg" "ggplot" 

Whaaattttt ???, что случилось с «Компактным дисплеем». Это не компактно!

И это может быть хуже, сумасшедший страшный, например, для объектов S4. Если вы хотите попробовать это:

library(rworldmap) 
newmap <- getMap(resolution = "coarse") 
str(newmap) 

Я не размещаю вывод здесь, потому что это слишком много. Он даже не подходит в консольном буфере!

Как вы можете понять внутреннюю структуру объекта с таким НЕ-компактным дисплеем? Это слишком много деталей, и вы легко теряетесь. Или, по крайней мере, я это делаю.

Ну, ладно. Прежде чем кто-нибудь скажет мне, эй checkout ?str и настроить аргументы, вот что я сделал. Конечно, это может поправиться, но я все еще разочарован str.

Лучшее решение у меня есть, чтобы создать функцию, сделать это

if(isS4(obj)){ 
    str(obj, max.level = 2, give.attr = FALSE, give.head = FALSE) 
} else { 
    str(obj, max.level = 1, give.attr = FALSE, give.head = FALSE) 
} 

Это показывает компактно верхние структуры уровня объекта. Выход для объекта зр выше (объект S4) становится гораздо более проницательным

Formal class 'SpatialPolygonsDataFrame' [package "sp"] with 5 slots 
    [email protected] data  :'data.frame': 243 obs. of 49 variables: 
    [email protected] polygons :List of 243 
    .. .. [list output truncated] 
    [email protected] plotOrder :7 135 28 167 31 23 9 66 84 5 ... 
    [email protected] bbox  :-180 -90 180 83.6 
    [email protected] proj4string:Formal class 'CRS' [package "sp"] with 1 slot 

Итак, теперь вы можете видеть, что есть 5 структур высшего уровня, и вы можете исследовать их далее по отдельности.

Похожие на объект ggplot выше, теперь вы можете увидеть

List of 9 
$ data  :Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 234 obs. of 11 variables: 
$ layers  :List of 1 
$ scales  :Classes 'ScalesList', 'ggproto' 
$ mapping :List of 2 
$ theme  : list() 
$ coordinates:Classes 'CoordCartesian', 'Coord', 'ggproto' 
$ facet  :List of 1 
$ plot_env : 
$ labels  :List of 2 

Хотя это гораздо лучше, я все еще чувствую, что это может быть гораздо более проницательными. Таким образом, возможно, кто-то чувствовал то же самое и создал приятную функцию, которая более информативна и по-прежнему компактно отображает информацию. Кто угодно?

+5

Я думаю, что проблема в том, что R делает это так легко определить новую структуру (S3, S4, R6, прото, пользовательский класс и т.д.) с произвольными уровнями nestedness, это трудно сделать по умолчанию ' str', который хорошо работает для всех случаев, особенно когда многие специальные классы не беспокоят определение полезной «str». Однако вы можете переопределить лучшие методы, и поскольку это функция только побочного эффекта, вы вряд ли сломаете что-то другое, кроме дисплеев. Я столкнулся с проблемой (ошибкой) с gtable и поэтому определил ['str.gtable' по своему усмотрению] (https://github.com/baptiste/gridextra/blob/master/R/gtable.r#L12). – baptiste

+7

Еще одна вещь, которую следует учитывать, - это проблеск() от dplyr. – joran

+0

Когда я хочу видеть содержимое объекта модели, я использую 'names', и я смотрю на страницу справки как для функции модели, так и для связанной с ней итоговой функции. Я полагаю, вы могли бы создать какой-то механизм отправки на основе класса, когда я получаю результаты «Hmisc :: описать (obj)» для данных, которые дают мой любимый набор сводных статистических данных, но «names (obj)» для более сложных списков. –

ответ

1

В такой ситуации я использую проблеск из пакета тиблей, который является менее подробным и кратко описывает структуру данных.

library(tibble) 
glimpse(gp) 
Смежные вопросы