Search code examples
rlistdataframeaggregatetabular

Convert a table into a list of data frames in R


I have a data frame with three variables: a grouping variable (Group) and categorical variables indicating if the group is new (New) and if its entry is delinquent (Delinquent).

Here are sample data:

df <- structure(list(Group = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 5L, 6L, 7L), .Label = c("A", "B", "C", "D", "E", "F", "G"), class = "factor"), New = c(FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE), Delinquent = c(FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE)), .Names = c("Group", "New", "Delinquent"), class = "data.frame", row.names = c(NA, -14L))
#df

I'm trying to count the number of delinquent groups, by whether they're new or not. To do this, I've wrapped table around aggregate on a simple data frame:

yo <- table(aggregate(Delinquent ~ Group + New, data = df, FUN = max))

which produces the rather odd output, an object of class "table"

yo
#, , Delinquent = 0
#
#     New
#Group FALSE TRUE
#    A     0    0
#    B     0    0
#    C     1    0
#    D     0    1
#    E     1    0
#    F     0    1
#    G     0    0
#
#, , Delinquent = 1
#
#     New
#Group FALSE TRUE
#    A     1    0
#    B     0    1
#    C     0    0
#    D     0    0
#    E     0    0
#    F     0    0
#    G     1    0

The output seems to be what I need to tally the number of delinquent groups by their status as new or not. Normally, I convert tables to data frames to interact with the data directly. However, in this case, I can't interact with the outputted table object or convert it successfully. I've tried converting it to a data frame via as.data.frame and as.data.frame.matrix and as a list via as.list and as.data.frame.list, but the converted output does not seem to be right. Using as.data.frame.array is the best I could come up with, but I was expecting a list of two separate data frames, one for each delinquency status. Any suggestions?

as.data.frame.array(yo)
#   FALSE.0 TRUE.0 FALSE.1 TRUE.1
# A       0      0       1      0
# B       0      0       0      1
# C       1      0       0      0
# D       0      1       0      0
# E       1      0       0      0
# F       0      1       0      0
# G       0      0       1      0

Solution

  • You should use as.data.frame.table.

    If you want to put everything into one data.frame:

    as.data.frame.table(yo)
    
       Group   New Delinquent Freq
    1      A FALSE          0    0
    2      B FALSE          0    0
    3      C FALSE          0    1
    4      D FALSE          0    0
    5      E FALSE          0    1
    ...
    

    If like you said you want a list of data.frames:

    (yolist <- apply(yo, 3, as.data.frame.table))
    
    $`0`
       Group   New Freq
    1      A FALSE    0
    2      B FALSE    0
    3      C FALSE    1
    4      D FALSE    0
    5      E FALSE    1
    ...
    
    $`1`
       Group   New Freq
    1      A FALSE    1
    2      B FALSE    0
    3      C FALSE    0
    4      D FALSE    0
    5      E FALSE    0
    ...
    
    sapply(yolist, class)
               0            1
    "data.frame" "data.frame"
    

    This works because your table is 3-dimensional array. The line above constructs a data.frame from a table sliced by appropriate index.