2

I am trying to use summarize, where the vector being summarized has names. The summarize function copies these names to the output, but the length is now wrong. When I try to format the resulting summary, the incorrect length of the names attribute throws an error.

In the example I really care about, the vector with names is the fitted.values from a glm model. I don't want the names, but they come for free. The toy example below uses mtcars.

``` r

library(tidyverse)
#> -- Attaching packages -------------------------------------------------------------------------------- tidyverse 1.2.1 --
#> v ggplot2 2.2.1     v purrr   0.2.4
#> v tibble  1.4.1     v dplyr   0.7.4
#> v tidyr   0.7.2     v stringr 1.2.0
#> v readr   1.1.1     v forcats 0.2.0
#> -- Conflicts ----------------------------------------------------------------------------------- tidyverse_conflicts() --
#> x dplyr::filter() masks stats::filter()
#> x dplyr::lag()    masks stats::lag()
# create a copy of mtcars, with the original mpg and a copy with names
namedmpg <- mtcars$mpg
attr(namedmpg, "names") <- row.names(mtcars)
MTCARS <- bind_cols(mtcars, namedmpg = namedmpg)

When I use the original mpg variable I get exactly what I want.

goodframe <- summarize(group_by(MTCARS, cyl), meanmpg = mean(mpg))
goodframe # gives exactly what we want
#> # A tibble: 3 x 2
#>     cyl meanmpg
#>   <dbl>   <dbl>
#> 1  4.00    26.7
#> 2  6.00    19.7
#> 3  8.00    15.1
format(goodframe$meanmpg) # formats fine
#> [1] "26.66364" "19.74286" "15.10000"

Now use the named mpg instead.

badframe <- summarize(group_by(MTCARS, cyl), meanmpg = mean(namedmpg))
badframe # seems to have what we want
#> # A tibble: 3 x 2
#>     cyl meanmpg
#>   <dbl>   <dbl>
#> 1  4.00    26.7
#> 2  6.00    19.7
#> 3  8.00    15.1
format(badframe$meanmpg) # throws an error
#> Error in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L, : 'names' attribute [32] must be the same length as the vector [3]
names(badframe$meanmpg) # the original names, which are now too many
#>  [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"

So I have to do something to get the summary in a form usable for further processing. Here is one hack.

format(badframe$meanmpg + 0) # a real hack, but seems to work

Of course there is always the old fashioned way

stillgood <- with(MTCARS, aggregate(namedmpg, list(cyl), mean))
stillgood
#>   Group.1        x
#> 1       4 26.66364
#> 2       6 19.74286
#> 3       8 15.10000
format(stillgood$x) # works
#> [1] "26.66364" "19.74286" "15.10000"

    ```

I am not sure if the situation is a bug or a feature. IMHO it should be documented either way.

In addition to the hack above, I could kill the names before the summarize. But I might want them someday.

Is there a better way?

1 Answers1

2

We could wrap with unname if that is acceptable

format(unname(badframe$meanmpg) )
#[1] "26.66364" "19.74286" "15.10000"
akrun
  • 874,273
  • 37
  • 540
  • 662
  • I like your suggestion, because it uses a standard R function designed for just this purpose. (As opposed to my hack.) I should have found this myself. I still am hoping to hear from a tidyverse person about the summarize function itself. – Bill Anderson Apr 17 '18 at 15:18