Question

I have a dataset which looks like this:

   t   x   y
1  0   0   0
2  1  10   9
3  2  20  18
4  3  30  27
...

I would like to collapse expand each row of the dataset vertically into a new column z. The goal would look something like this:

   t   z
1  0   0
2  0   0
3  1  10
4  1   9
5  2  20
6  2  18
7  3  30
8  3  27
...

In Python, I would use itertools.chain for this purpose:

import itertools

# Make some fake data
data = [{'t':t, 'x':t*10, 'y':t*9} for t in xrange(10)]
# [ {'t': 0, 'y':  0, 'x':  0},
#   {'t': 1, 'y':  9, 'x': 10},
#   {'t': 2, 'y': 18, 'x': 20},
# ...]

# transformation...
list(itertools.chain(*(({'t':x['t'], 'z':x['x']}, {'t':x['t'], 'z':x['y']})
                        for x in data)
     ))
# [{'z':  0, 't': 0},
#  {'z':  0, 't': 0},
#  {'z': 10, 't': 1},
#  {'z':  9, 't': 1},
#  {'z': 20, 't': 2},
#  {'z': 18, 't': 2},
# ...]

I've made a ton of different attempts with the reshape package (melt grouped by t seems so close to what I want, but sorting by t isn't stable, as far as I can tell).

Was it helpful?

Solution

library(reshape2)
df2 <- melt(df, id.vars = "t")
df2
#   t variable value
# 1 0        x     0
# 2 1        x    10
# 3 2        x    20
# 4 3        x    30
# 5 0        y     0
# 6 1        y     9
# 7 2        y    18
# 8 3        y    27

Possibly order rows, and select relevant columns.

df2[order(df2$t), c("t", "value")]
#   t value
# 1 0     0
# 5 0     0
# 2 1    10
# 6 1     9
# 3 2    20
# 7 2    18
# 4 3    30
# 8 3    27

OTHER TIPS

You could achieve this with, for example

dfx.temp <- df[,c(1,2)]
dfy.temp <- df[,c(1,2)]
names(dfx.temp) <- c("t","z")
names(dfy.temp) <- c("t","z")
df <- rbind(dfx.temp, dfy.temp)

Add df <- df[order(df$t),] to get it in the exact order you asked for.

Here are two other options...

Like melt, but in base R:

out <- cbind(t = mydf[, 1], stack(mydf[-1]))
out[order(out$t, out$ind), c("t", "values")]
#   t values
# 1 0      0
# 5 0      0
# 2 1     10
# 6 1      9
# 3 2     20
# 7 2     18
# 4 3     30
# 8 3     27

A "data.table" approach:

library(data.table)
DT <- data.table(mydf)
DT[, unlist(.SD), by = "t"]
#    t V1
# 1: 0  0
# 2: 0  0
# 3: 1 10
# 4: 1  9
# 5: 2 20
# 6: 2 18
# 7: 3 30
# 8: 3 27

Both examples use the following as "mydf":

mydf <- data.frame(t = 0:3, x = seq(0, 30, 10), y = seq(0, 27, 9))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top