Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a dataframe into a nested list?

I have a dataframe that I want to convert to a nested list with a custom level of nesting. This is how I do it, but I'm sure there is a better way:

data <- data.frame(city=c("A", "A", "B", "B"), street=c("a", "b", "a", "b"), tenant=c("Smith","Jones","Smith","Jones"), income=c(100,200,300,400))

nested_data <- lapply(levels(data$city), function(city){
    data_city <- subset(data[data$city == city, ], select=-city)
    list(city = city, street_values=lapply(levels(data_city$street), function(street){
        data_city_street <- subset(data_city[data_city$street == street, ], select=-street)
        tenant_values <- apply(data_city_street, 1, function(income_tenant){
            income_tenant <- as.list(income_tenant)
            list(tenant=income_tenant$tenant, income=income_tenant$income)
        })
        names(tenant_values) <- NULL
        list(street=street, tenant_values=tenant_values)
    }))
})

The output in JSON looks like:

library(rjson)
write(toJSON(nested_data), "")
[{"city":"A","street_values":[{"street":"a","tenant_values":[{"tenant":"Smith","income":"100"}]},{"street":"b","tenant_values":[{"tenant":"Jones","income":"200"}]}]},{"city":"B","street_values":[{"street":"a","tenant_values":[{"tenant":"Smith","income":"300"}]},{"street":"b","tenant_values":[{"tenant":"Jones","income":"400"}]}]}]

# or prettified:

[
  {
    "city": "A",
    "street_values": [
      {
        "street": "a",
        "tenant_values": [
          {
            "tenant": "Smith",
            "income": "100"
          }
        ]
      },
      {
        "street": "b",
        "tenant_values": [
          {
            "tenant": "Jones",
            "income": "200"
          }
        ]
      }
    ]
  },
  {
    "city": "B",
    "street_values": [
      {
        "street": "a",
        "tenant_values": [
          {
            "tenant": "Smith",
            "income": "300"
          }
        ]
      },
      {
        "street": "b",
        "tenant_values": [
          {
            "tenant": "Jones",
            "income": "400"
          }
        ]
      }
    ]
  }
]

Is there a better way to do this?

like image 580
nachocab Avatar asked Mar 04 '13 16:03

nachocab


People also ask

How do you convert a DataFrame to a list?

To convert Pandas DataFrame to List in Python, use the DataFrame. values(). tolist() function.

Can a DataFrame be nested?

Grouped data framesdf %>% nest(data = c(x, y)) specifies the columns to be nested; i.e. the columns that will appear in the inner data frame. Alternatively, you can nest() a grouped data frame created by dplyr::group_by() . The grouping variables remain in the outer data frame and the others are nested.


1 Answers

What about using split to get you most of the way, and rapply for the last step:

nestedList <- rapply(lapply(split(data[-1], data[1]), 
                            function(x) split(x[-1], x[1])), 
                     f = function(x) as.character(unlist(x)), 
                     how = "replace")

Here's the output:

nestedList
# $A
# $A$a
# $A$a$tenant
# [1] "Smith"
# 
# $A$a$income
# [1] "100"
# 
# 
# $A$b
# $A$b$tenant
# [1] "Jones"
# 
# $A$b$income
# [1] "200"
# 
# 
# 
# $B
# $B$a
# $B$a$tenant
# [1] "Smith"
# 
# $B$a$income
# [1] "300"
# 
# 
# $B$b
# $B$b$tenant
# [1] "Jones"
# 
# $B$b$income
# [1] "400"

And the structure:

> str(nestedList)
List of 2
 $ A:List of 2
  ..$ a:List of 2
  .. ..$ tenant: chr "Smith"
  .. ..$ income: chr "100"
  ..$ b:List of 2
  .. ..$ tenant: chr "Jones"
  .. ..$ income: chr "200"
 $ B:List of 2
  ..$ a:List of 2
  .. ..$ tenant: chr "Smith"
  .. ..$ income: chr "300"
  ..$ b:List of 2
  .. ..$ tenant: chr "Jones"
  .. ..$ income: chr "400"

The structure doesn't exactly match what you're looking for, but this might help get you started with an alternative approach.

like image 125
A5C1D2H2I1M1N2O1R2T1 Avatar answered Sep 21 '22 23:09

A5C1D2H2I1M1N2O1R2T1