Question

I have a data frame similar to the following example:

> df <- data.frame(imp = c("Johny", "Johny", "Lisa", "Max"), item = c(5025, 1101, 2057, 1619))
> df
     imp     item  
[1,] "Johny" "5025"
[2,] "Johny" "1101"
[3,] "Lisa"  "2057"
[4,] "Max"   "1619"

I would like to have an unique row for each user. The final result should be something like this:

> df
     imp     item1  item2 
[1,] "Johny" "5025" "1101"
[2,] "Lisa"  "2057" NA    
[3,] "Max"   "1619" NA
Was it helpful?

Solution

## Add an ID column to distinguish multiple measurements per imp
## There's probably a better way to do this?
df <- do.call(rbind, lapply(
    split(df, df$imp),
    function(x) {
        x$item_id <- seq(nrow(x))
        return(x)
    }
))

## Then simply use the dcast function from the reshape2 package
df <- dcast(df, imp ~ item_id, value.var='item')

## Tidy up the column names
names(df) <- sub('^(\\d+)$', 'item_\\1', names(df))

OTHER TIPS

Using data.table v 1.9.6+ we can pass expressions directly to formula. Please see ?dcast for more and also the examples section.

require(data.table) # v1.9.6+
dcast(setDT(df), imp ~ paste0("item", 
       df[, seq_len(.N), by=imp]$V1), value.var="item")

#      imp item1 item2
# 1: Johny  5025  1101
# 2:  Lisa  2057    NA
# 3:   Max  1619    NA

Edit:

Using data.table v1.9.8+ you could simply do

require(data.table) # v1.9.8+
dcast(setDT(df), imp ~ rowid(imp, prefix = "item"), value.var = "item")

what about this approach using data.table:

require(data.table)
dt <- data.table(imp = c("Johny", "Johny", "Lisa", "Max"),
                 item = c(5025, 1101, 2057, 1619))

dt[, list(items = list(unique(item))), by=imp]

# to keep all items, not only uniques
dt[, list(items = list(item)), by=imp]

this provides you with a list of "items" for every "imp"...

Here's a way to do it in base R with ave (to create your "time" variable) and reshape (to go from "long" to "wide"):

df$times <- ave(rep(1, nrow(df)), df$imp, FUN = seq_along)
df
#     imp item times
# 1 Johny 5025     1
# 2 Johny 1101     2
# 3  Lisa 2057     1
# 4   Max 1619     1
reshape(df, direction = "wide", idvar="imp", timevar="times")
#     imp item.1 item.2
# 1 Johny   5025   1101
# 3  Lisa   2057     NA
# 4   Max   1619     NA
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top