Рефрейминг магии на data.frame

В настоящее время я участвую в работе с data.frame и довольно смущен тем, как их изменить.

На данный момент у меня есть data.frame, который показывает:

  • столбец 1: название магазина
  • столбец 2: продукт
  • столбец 3: номер покупки этого продукта в этом магазине

или визуально что-то вроде этого:

+---+-----------+-------+----------+--+
|   | Shop.Name | Items | Product  |  |
+---+-----------+-------+----------+--+
| 1 | Shop1     |     2 | Product1 |  |
| 2 | Shop1     |     4 | Product2 |  |
| 3 | Shop2     |     3 | Product1 |  |
| 4 | Shop3     |     2 | Product1 |  |
| 5 | Shop3     |     1 | Product4 |  |
+---+-----------+-------+----------+--+

То, что я хотел бы достичь, - это следующая "ориентированная на магазины" структура:

  • столбец 1: название магазина
  • столбец 2: Товары, проданные для продукта1
  • столбец 3: Товары, проданные для продукта2
  • столбец 4: Товары, проданные для продукта3 ...

Если для определенного магазина/продукта нет линии (из-за отсутствия продаж), я хотел бы создать 0.

или

+---+-------+-------+-------+-------+-------+-----+--+--+
|   | Shop  | Prod1 | Prod2 | Prod3 | Prod4 | ... |  |  |
+---+-------+-------+-------+-------+-------+-----+--+--+
| 1 | Shop1 |     2 |     4 |     0 |     0 | ... |  |  |
| 2 | Shop2 |     3 |     0 |     0 |     0 | ... |  |  |
| 3 | Shop3 |     2 |     0 |     0 |     1 | ... |  |  |
+---+-------+-------+-------+-------+-------+-----+--+--+

Ответ 1

Ответы до сих пор работают в определенной степени, но не полностью отвечают на ваш вопрос. В частности, они не рассматривают вопрос о случае, когда нет магазинов, продающих определенный продукт. Из вашего примера ввода и желаемого вывода не было магазинов, которые продавали "Product3". Действительно, "Product3" даже не появляется в вашем источнике data.frame. Кроме того, они не учитывают возможную ситуацию с наличием более чем одной строки для каждой комбинации Shop + Product.

Здесь представлена ​​измененная версия ваших данных и два решения. Я добавил еще одну строку для комбинации "Shop1" и "Product1". Обратите внимание, что я преобразовал ваши продукты в переменную factor, которая включает уровни, которые может принимать переменная, даже если ни один из случаев не имеет этого уровня.

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? Внезапно не работает. Сделайте это вместо:

    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
    
  • Позвольте быть oldschool. cast из "изменить форму"

    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
    

    Э. Не то, что вы хотели снова... Попробуйте это вместо:

    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
    
  • Вернемся к основам. xtabs из базы 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
    

    Или, если вы предпочитаете data.frame (обратите внимание, что ваша переменная "Shop.Name" была преобразована в row.names 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
    

Ответ 2

Используйте dcast в библиотеке reshape2:

library(reshape2)

> df <- data.frame(Shop.Name=rep(c("Shop1","Shop2","Shop3"),each=3),
+                  Items=rpois(9,5),
+                  Product=c(rep(c("Prod1","Prod2","Prod3","Prod4"),2),"Prod5")
+ )
> df
  Shop.Name Items Product
1     Shop1     6   Prod1
2     Shop1     5   Prod2
3     Shop1     6   Prod3
4     Shop2     5   Prod4
5     Shop2     6   Prod1
6     Shop2     6   Prod2
7     Shop3     4   Prod3
8     Shop3     7   Prod4
9     Shop3     5   Prod5
> dcast(df,Shop.Name ~ Product,value.var="Items",fill=0)
  Shop.Name Prod1 Prod2 Prod3 Prod4 Prod5
1     Shop1     6     5     6     0     0
2     Shop2     6     6     0     5     0
3     Shop3     0     0     4     7     5

Ответ 3

Если вы хотите использовать исходный пакет reshape по любой причине:

Shop.Name <- c("Shop1", "Shop1", "Shop2", "Shop3", "Shop3")
Items <- c(2,4,3,2,1)
Product <- c("Product1", "Product2", "Product1", "Product1", "Product4")
(df <- data.frame(Shop.Name, Items, Product))

cast(df, formula = Shop.Name ~ Product, value="Items", fill=0)