Question

I have a dataframe that looks like this:

created_at  actor_attributes_email      type
3/11/12 7:28    jeremy@asynk.ch         PushEvent
3/11/12 7:28    jeremy@asynk.ch         PushEvent
3/11/12 7:28    jeremy@asynk.ch         PushEvent
3/11/12 7:42    jeremy@asynk.ch         IssueCommentEvent
3/11/12 11:06   d.bussink@gmail.com     PushEvent
3/11/12 11:06   d.bussink@gmail.com     PushEvent

Now I want to rearrange it by month/year (still sorted by time, and still maintaining the integrity of the rows). That should create 3 columns for each month, and then put all the data relevant to that month (created_at, actor_attributes_email, & type) in those 3 columns, so that I get the following headers (for all the months present in the data):

april_2011_created_at april_2011_actor_attributes_email april_2011_type may_2011_created_at may_2011_actor_attributes_email may_2011_type  

How can I accomplish this in R?

The CSV file with the entire dataset can be found here: https://github.com/aronlindberg/VOSS-Sequencing-Toolkit/blob/master/rubinius_rubinius_sequencing/rubinius_6months.csv

Here is a dput() of the first rows of the CSV:

structure(list(created_at = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 
3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L, 6L, 6L, 6L, 7L, 7L, 7L, 8L, 
8L, 8L, 9L, 9L, 9L, 10L, 10L, 10L), .Label = c("2012-03-11 07:28:04", 
"2012-03-11 07:28:19", "2012-03-11 07:42:16", "2012-03-11 11:06:13", 
"2012-03-11 12:46:25", "2012-03-11 13:03:12", "2012-03-11 13:12:34", 
"2012-03-11 13:14:52", "2012-03-11 13:30:14", "2012-03-11 13:30:48"
), class = "factor"), actor_attributes_email = structure(c(3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("", 
"d.bussink@gmail.com", "jeremy@asynk.ch"), class = "factor"), 
    type = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L), .Label = c("IssueCommentEvent", "PushEvent"
    ), class = "factor")), .Names = c("created_at", "actor_attributes_email", 
"type"), class = "data.frame", row.names = c(NA, -30L))

Some other assumptions are:

  • Even if "PushEvent" (for example) is repeated 10x I need to retain all of these, since I will be doing sequence analysis using the R package TraMineR
  • Columns can be of unequal length
  • There is no relationship between the columns for different months
  • Data within a certain month should be sorted with the earliest time first
  • Data from, say, June 2011 and June 2012 need to be in separate columns
Was it helpful?

Solution

Maiasaura provided an elegant way to get the job done with plyr and lubridate. Here is the slightly less elegant way to accomplish it in base R. But unlike Maiasaura's, this way minimizes the number of NA rows. The number NA rows for each month is the difference between the number of rows for that month and the maximum number of rows for any month.

# split df by month
by.mon <- split(df, months(as.POSIXct(df$created_at)))

# rename the columns to include the month name
by.mon <- mapply(
    function(x, mon.name) {
        names(x) <- paste(mon.name, names(x), sep='_');
        return(x)
    }, x=by.mon, mon.name=names(by.mon), SIMPLIFY=FALSE)

# add an index column for merging on
by.mon.indexed <- lapply(by.mon, function(x) within(x, index <- 1:nrow(x)))

# merge all of the months together
results <- Reduce(function(x, y) merge(x, y, by='index', all=TRUE, sort=FALSE), 
    by.mon.indexed)

# remove the index column
final_result <- results[names(results) != 'index']

OTHER TIPS

library(plyr)
library(lubridate)
df$created_at <- ymd_hms(df$created_at, quiet = TRUE)
df$mname <- as.character(lubridate::month(df$created_at,label = T, abbr = T))
result <- dlply(df, .(mname), function(x){
      x <- arrange(x, created_at)
      names(x) <- paste0(unique(x$mname), "_", names(x))
      x$mname <- NULL
      x
    }, .progress = 'text')

final_result <- ldply(result, rbind.fill)[, -1]

Note that since you want the month name appended to the 3 column names and the appropriate data filled in, all the columns for which there are no data will just get filled with NAs (which is the intended behavior of rbind.fill).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top