Search code examples
rarraysdataframecrosstab

How to create table or named array in R when I already have the cell values?


Given a dataframe such as:

df = data.frame(
  Bread=rep(c("White", "Wheat", "Rye"), each=4),
  Meat=rep(c("Ham", "Roast Beef", "Turkey", "Pastrami"), times=3),
  Price=rnorm(12)
)
df
#>    Bread       Meat      Price
#> 1  White        Ham  0.6428015
#> 2  White Roast Beef -0.4382468
#> 3  White     Turkey -0.9383151
#> 4  White   Pastrami  1.6069649
#> 5  Wheat        Ham -0.9898017
#> 6  Wheat Roast Beef  0.4567167
#> 7  Wheat     Turkey  0.9479741
#> 8  Wheat   Pastrami -0.5721409
#> 9    Rye        Ham  0.1234204
#> 10   Rye Roast Beef -1.1446393
#> 11   Rye     Turkey -2.8622073
#> 12   Rye   Pastrami -1.1646482

Created on 2020-06-02 by the reprex package (v0.3.0)

I would like to make a table such as this but filled with the values.

+-------+-----+--------+------------+----------+
|       | Ham | Turkey | Roast Beef | Pastrami |
+-------+-----+--------+------------+----------+
| White |     |        |            |          |
+-------+-----+--------+------------+----------+
| Wheat |     |        |            |          |
+-------+-----+--------+------------+----------+
| Rye   |     |        |            |          |
+-------+-----+--------+------------+----------+

Afterwards, I'd like to add dimnames such as "Bread Type" and "Meat Selection."

I tried using spread, but I can't figure out how to turn the final dataframe into a table object.

tidyr::spread(df, Bread, Price)
#>         Meat        Rye      Wheat      White
#> 1        Ham  1.4325955  0.2399214 -1.3911592
#> 2   Pastrami  0.3127256  0.1133108  0.1940318
#> 3 Roast Beef -1.6286526  0.8210128 -0.4017497
#> 4     Turkey -0.8071035 -0.2611048 -0.9201723

Created on 2020-06-02 by the reprex package (v0.3.0)


Solution

  • We can use pivot_wider with column_to_rownames from tibble

    library(dplyr)
    library(tibble)
    library(tidyr)
    df %>% 
           pivot_wider(names_from = Meat, values_from = Price) %>%
           column_to_rownames('Bread') %>%
           as.matrix
    #             Ham Roast Beef     Turkey    Pastrami
    #White  0.3881185  0.2906277 -0.2855983  0.07601472
    #Wheat -0.5602986  0.4471884  0.9085011 -0.50505960
    #Rye   -0.3010040 -0.7260360 -1.1800770  0.25307471
    

    Or with acast

    library(reshape2)
    acast(df, Bread ~ Meat)
    

    Or with xtabs from base R

    out <- xtabs(Price ~ Bread + Meat, df)
    names(dimnames(out)) <- c("Bread Type", "Meat Selection")
    out
    #          Meat Selection
    #Bread Type         Ham    Pastrami  Roast Beef      Turkey
    #     Rye   -0.30100401  0.25307471 -0.72603598 -1.18007703
    #     Wheat -0.56029860 -0.50505960  0.44718837  0.90850113
    #     White  0.38811847  0.07601472  0.29062767 -0.28559829