Reframing magic on data.frame
dataframe, r, reshape
Solution
The answers so far work to a certain degree, but don't fully answer your question. In particular, they don't address the issue of a case in which there are no shops which sold a particular product. From your example input and desired output, there were no shops which sold "Product3". Indeed, "Product3" does not even appear in your source `data.frame`. Additionally, they do not address the possible situation of having more than one row for each Shop + Product combination.
Here's a modified version of your data and the two solutions so far. I've added another row for a combination of "Shop1" and "Product1". Notice that I have converted your products to a `factor` variable that includes the levels that the variable can take, even if none of the cases actually has that level.
mydf <- data.frame(
Shop.Name = c("Shop1", "Shop1", "Shop2", "Shop3", "Shop3", "Shop1"),
Items = c(2, 4, 3, 2, 1, 2),
Product = factor(
c("Product1", "Product2", "Product1", "Product1", "Product4", "Product1"),
levels = c("Product1", "Product2", "Product3", "Product4")))
`dcast` from "reshape2"
library(reshape2)
dcast(mydf, formula = Shop.Name ~ Product, value="Items", fill=0)
# Using Product as value column: use value.var to override.
# Aggregation function missing: defaulting to length
# Error in .fun(.value[i], ...) :
# 2 arguments passed to 'length' which requires 1
Wha? Suddenly does not work. Do this instead:
dcast(mydf, formula = Shop.Name ~ Product,
fill = 0, value.var = "Items",
fun.aggregate = sum, drop = FALSE)
# Shop.Name Product1 Product2 Product3 Product4
# 1 Shop1 4 4 0 0
# 2 Shop2 3 0 0 0
# 3 Shop3 2 0 0 1
Let's be oldschool. `cast` from "reshape"
library(reshape)
cast(mydf, formula = Shop.Name ~ Product, value="Items", fill=0)
# Aggregation requires fun.aggregate: length used as default
# Shop.Name Product1 Product2 Product4
# 1 Shop1 2 1 0
# 2 Shop2 1 0 0
# 3 Shop3 1 0 1
Eh. Not what you wanted again... Try this instead:
cast(mydf, formula = Shop.Name ~ Product,
value = "Items", fill = 0,
add.missing = TRUE, fun.aggregate = sum)
# Shop.Name Product1 Product2 Product3 Product4
# 1 Shop1 4 4 0 0
# 2 Shop2 3 0 0 0
# 3 Shop3 2 0 0 1
Let's get back to basics. `xtabs` from base R
xtabs(Items ~ Shop.Name + Product, mydf)
# Product
# Shop.Name Product1 Product2 Product3 Product4
# Shop1 4 4 0 0
# Shop2 3 0 0 0
# Shop3 2 0 0 1
Or, if you prefer a `data.frame` (note that your "Shop.Name" variable has been converted to the `row.names` of the `data.frame`):
as.data.frame.matrix(xtabs(Items ~ Shop.Name + Product, mydf))
# Product1 Product2 Product3 Product4
# Shop1 4 4 0 0
# Shop2 3 0 0 0
# Shop3 2 0 0 1
Problem
I am currently learning to work with data.frame and quite confused on how to reorder them. At the moment, I have a data.frame that shows : - column 1: a shop name - column 2: a product - column 3: the number of purchase for this product by this shop or visually something like this: ``` +---+-----------+-------+----------+--+ | | Shop.Name | Items | Product | | +---+-----------+-------+----------+--+ | 1 | Shop1 | 2 | Product1 | | | 2 | Shop1 | 4 | Product2 | | | 3 | Shop2 | 3 | Product1 | | | 4 | Shop3 | 2 | Product1 | | | 5 | Shop3 | 1 | Product4 | | +---+-----------+-------+----------+--+ ``` What I would like to achieve is the following "shop-centric" structure: - column 1: a shop name - column 2: Items sold for product1 - column 3: Items sold for product2 - column 4: Items sold for product3 ... When there is no line for a specific shop/product (because of no sales), I would like to create a 0. or ``` +---+-------+-------+-------+-------+-------+-----+--+--+ | | Shop | Prod1 | Prod2 | Prod3 | Prod4 | ... | | | +---+-------+-------+-------+-------+-------+-----+--+--+ | 1 | Shop1 | 2 | 4 | 0 | 0 | ... | | | | 2 | Shop2 | 3 | 0 | 0 | 0 | ... | | | | 3 | Shop3 | 2 | 0 | 0 | 1 | ... | | | +---+-------+-------+-------+-------+-------+-----+--+--+ ```