Skip to content

Instantly share code, notes, and snippets.

Created May 24, 2013 10:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/5642621 to your computer and use it in GitHub Desktop.
Save anonymous/5642621 to your computer and use it in GitHub Desktop.
R reshaping in Groovy

From the simple R example of reshape here, given a List of Maps like this:

data = [ [ id: 1, time: 1, x1: 5, x2: 6 ],
         [ id: 1, time: 2, x1: 3, x2: 5 ],
         [ id: 2, time: 1, x1: 6, x2: 1 ],
         [ id: 2, time: 2, x1: 2, x2: 4 ] ]

And the methods melt:

List melt( List data, List keys ) {
  data.collectMany {
    it.subMap( keys ).with { k ->
      ( it - k ).inject( [] ) { r, v -> 
        r << ( k + [ key:v.key, value:v.value ] )
      }
    }
  }
}

and cast:

List cast( List data, String subject, Closure fn ) {
  data.groupBy( { it[ subject ] } ).collect { k, v ->
    v.groupBy( { it[ 'key' ] } ).collectEntries { k2, v2 ->
      fn( v2.value ).with { f ->
        [ (subject): k, (k2): f ]
      }
    }
  }
}

We can first melt our data with:

def a = melt( data, [ 'id', 'time' ] )

Which gives us the List of Maps:

[ [ id:1, time:1, key:x1, value:5 ],
  [ id:1, time:1, key:x2, value:6 ],
  [ id:1, time:2, key:x1, value:3 ],
  [ id:1, time:2, key:x2, value:5 ],
  [ id:2, time:1, key:x1, value:6 ],
  [ id:2, time:1, key:x2, value:1 ],
  [ id:2, time:2, key:x1, value:2 ],
  [ id:2, time:2, key:x2, value:4 ] ]

We can then get the mean value of x1 and x2 by id using:

def avgById = cast( a, 'id' ) {
  it.sum() / it.size()
}

// [ [ id:1, x1:4, x2:5.5 ],
//   [ id:2, x1:4, x2:2.5 ] ]

Or by time by:

def avgByTime = cast( a, 'time' ) {
  it.sum() / it.size()
}

// [ [ time:1, x1:5.5, x2:3.5 ],
//   [ time:2, x1:2.5, x2:4.5 ] ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment