2016-03-04 2 views
1

Образец данных:Вставить преобразование в новую строку, а не колонки

Date <- as.Date(c('1-01-2008','2-01-2008', '3-01-2008', '1-01-2008','2-01- 2008', '3-01-2008','1-01-2008','2-01-2008', '3-01-2008', '1-01-2008','2-01-2008', '3-01-2008'), format = "%m-%d-%Y") 
Country <- c('US', 'US','US', 'JP', 'JP', 'JP', 'US', 'US','US', 'JP', 'JP', 'JP') 
Category <- c('Apple', 'Apple', 'Apple', 'Apple', 'Apple', 'Apple', 'foo', 'foo','foo', 'foo','foo', 'foo') 
Value <- c(runif(12, -0.5, 10)) 
df <- data.frame(Date, Country, Category, Value) 

То, что я хочу сделать, это вычесть для каждого месяца и в каждой стране значения Apple, и обув (так для США и 2008-01- 01 значение будет -1.2357797). Однако я хочу, чтобы вставить результат в виде строки, с указанием категории, например. «Дифференциал».

я понял, как сделать это с dplyr/мутировать, но только вставив целый новый столбец, в этом случае таблица не имеет смысла больше (как категории не подходят и я преобразования в список ниже):

df <- df %>% 
group_by(Country, Date) %>% 
    mutate(
     diff = Value[Category=="Apple"] - Value[Category=="foo"]) 

Edit: Важно: Я хочу добавить несколько преобразований таким образом, не только различия, упомянутые в данном примере.

Редактировать2: Спасибо за все полезные ответы. Используя метод tidyr/dplyr предложенный @akrun я буду использовать это, чтобы вставить больше преобразований:

library(tidyr) 
library(dplyr) 
df <- spread(df, Category, Value) %>% 
    mutate(diff=Apple- foo, xyz = Apple+foo) %>% 
    gather(Category, Value, Apple:diff, Apple:xyz) 
+0

В правки, вместо 'собрать (категория, стоимость, Apple: Diff, Apple: хуг)' вы должны просто использовать 'собрать (категория, стоимость, Apple: хуг)' –

ответ

3

Мы можем использовать либо data.table или dplyr. С помощью data.table преобразуйте «data.frame» в «data.table» (setDT(df)), сгруппированные по «Дата», «Страна», мы получаем разницу «Значение» для соответствующих значений «Apple» и «foo» в ' Категория ", а также создать« Категория »с« diff »в качестве значения. Это будет новый обобщенный набор данных ('dfN'), который мы можем rbind с исходным набором данных с использованием rbindlist. При необходимости, мы можем order на 'Дата', 'Страна'

library(data.table) 
dfN <- setDT(df)[, 
    list(Category="diff", 
     Value=Value[Category=="Apple"]- Value[Category=="foo"]), 
       by = .(Date, Country)] 
rbindlist(list(df, dfN))[order(Date,Country)] 
#  Date Country Category  Value 
# 1: 2008-01-01  JP Apple 9.8861949 
# 2: 2008-01-01  JP  foo 6.8009149 
# 3: 2008-01-01  JP  diff 3.0852799 
# 4: 2008-01-01  US Apple -0.3047560 
# 5: 2008-01-01  US  foo 9.1748432 
# 6: 2008-01-01  US  diff -9.4795991 
# 7: 2008-02-01  JP Apple 8.7836616 
# 8: 2008-02-01  JP  foo 5.4775849 
# 9: 2008-02-01  JP  diff 3.3060767 
#10: 2008-02-01  US Apple 1.6155057 
#11: 2008-02-01  US  foo 3.6720346 
#12: 2008-02-01  US  diff -2.0565289 
#13: 2008-03-01  JP Apple 1.9879906 
#14: 2008-03-01  JP  foo 7.1387297 
#15: 2008-03-01  JP  diff -5.1507391 
#16: 2008-03-01  US Apple 1.1435151 
#17: 2008-03-01  US  foo 0.6596238 
#18: 2008-03-01  US  diff 0.4838913 

Или другой вариант использует dcast/melt из data.table

melt(dcast(setDT(df), Date+Country~Category, 
    value.var='Value')[, diff:= Apple-foo], 
     id.var=c('Date', 'Country')) 

Если мы используем опцию gather/spread (аналогично до melt/dcast) от tidyr,

library(tidyr) 
library(dplyr) 
spread(df, Category, Value) %>% 
     mutate(diff=Apple- foo) %>% 
     gather(Category, Value, Apple:diff) 

Или используйте dplyr, мы используем ту же технику, а не rbindlist, мы делаем с bind_rows.

library(dplyr) 
df %>% 
    group_by(Country, Date) %>% 
    summarise(Value = Value[Category=="Apple"] - 
         Value[Category=="foo"], 
       Category= "diff") %>% 
    bind_rows(df, .) %>% 
    arrange(Date, Country) 
#  Date Country Category  Value 
#  (date) (fctr) (chr)  (dbl) 
#1 2008-01-01  JP Apple 9.8861949 
#2 2008-01-01  JP  foo 6.8009149 
#3 2008-01-01  JP  diff 3.0852799 
#4 2008-01-01  US Apple -0.3047560 
#5 2008-01-01  US  foo 9.1748432 
#6 2008-01-01  US  diff -9.4795991 
#7 2008-02-01  JP Apple 8.7836616 
#8 2008-02-01  JP  foo 5.4775849 
#9 2008-02-01  JP  diff 3.3060767 
#10 2008-02-01  US Apple 1.6155057 
#11 2008-02-01  US  foo 3.6720346 
#12 2008-02-01  US  diff -2.0565289 
#13 2008-03-01  JP Apple 1.9879906 
#14 2008-03-01  JP  foo 7.1387297 
#15 2008-03-01  JP  diff -5.1507391 
#16 2008-03-01  US Apple 1.1435151 
#17 2008-03-01  US  foo 0.6596238 
#18 2008-03-01  US  diff 0.4838913 
+0

Спасибо! ваш первый метод работает отлично, но метод dplyr дает мне ошибку: * length (rows) == 1 не TRUE *. Одна вещь, которую я должен упомянуть: я хочу добавить несколько преобразований таким образом. Я смутно знаю, что с dplyr я могу просто добавить больше аргументов, но с помощью метода data.table. Я немного смущен тем, где добавлять новые аргументы, поскольку они отображаются как отдельные столбцы в dfN. – Dreica

+0

@Dreica Можете ли вы проверить метод dplyr сейчас. Я обновил сообщение. – akrun

+0

@Dreica После создания этого столбца вы можете выполнить дальнейшую трансформацию. Не знаете, как вы хотели это сделать, если не предоставлен более конкретный пример. Что касается объема этого вопроса, это дает ожидаемый ответ. – akrun