The answer will depend on the format of category_list . If in fact it is a list for each row
Sort of
mydf <- data.frame(ID = paste0('ID',1:3), category_list = I(list(c('cat1','cat2','cat3'), c('cat2','cat3'), c('cat1'))), xval = 1:3, yval = 1:3)
or
library(data.table) mydf <- as.data.frame(data.table(ID = paste0('ID',1:3), category_list = list(c('cat1','cat2','cat3'), c('cat2','cat3'), c('cat1')), xval = 1:3, yval = 1:3) )
Then you can use plyr and merge to create your long form data
newdf <- merge(mydf, ddply(mydf, .(ID), summarize, cat_list = unlist(category_list)), by = 'ID') ID category_list xval yval cat_list 1 ID1 cat1, cat2, cat3 1 1 cat1 2 ID1 cat1, cat2, cat3 1 1 cat2 3 ID1 cat1, cat2, cat3 1 1 cat3 4 ID2 cat2, cat3 2 2 cat2 5 ID2 cat2, cat3 2 2 cat3 6 ID3 cat1 3 3 cat1
or non-plyr approach that does not require merge
do.call(rbind,lapply(split(mydf, mydf$ID), transform, cat_list = unlist(category_list)))