Создать новый индикатор отношения в длинных данных в R
У меня длинный фрейм данных
mydf <- data.frame(
+ date=c("2016-01-01","2016-02-01","2016-03-01","2016-04-01","2016-05-01", "2016-02-01", "2016-03-01", "2016-04-01", "2016-05-01", "2016-06-01"),
+ value=c(1,2,3,4,5,1,2,3,4,5),
+ country=c("US", "US", "US", "US", "US", "US", "US", "US", "US", "US"),
+ indicator=c("gdp", "gdp", "gdp", "gdp", "gdp", "population", "population", "population", "population", "population"))
date value country indicator
1 2016-01-01 1 US gdp
2 2016-02-01 2 US gdp
3 2016-03-01 3 US gdp
4 2016-04-01 4 US gdp
5 2016-05-01 5 US gdp
6 2016-02-01 1 US population
7 2016-03-01 2 US population
8 2016-04-01 3 US population
9 2016-05-01 4 US population
10 2016-06-01 5 US population
Я хочу создать конкретные новые показатели, которые исходят из соотношений, например. ВВП/население * 1000
Это будет выглядеть примерно так, он должен соответствовать правильным датам для каждого соответствующего индикатора
mydf <- data.frame(
+ date=c("2016-01-01","2016-02-01","2016-03-01","2016-04-01","2016-05-01", "2016-02-01", "2016-03-01", "2016-04-01", "2016-05-01", "2016-06-01", "2016-02-01", "2016-03-01", "2016-04-01", "2016-05-01"),
+ value=c(1,2,3,4,5,1,2,3,4,5,2,1.5,1.33,1.2),
+ country=c("US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US"),
+ indicator=c("gdp", "gdp", "gdp", "gdp", "gdp", "population", "population", "population", "population", "population", "gdp per capita", "gdp per capita", "gdp per capita", "gdp per capita"))
date value country indicator
1 2016-01-01 1.00 US gdp
2 2016-02-01 2.00 US gdp
3 2016-03-01 3.00 US gdp
4 2016-04-01 4.00 US gdp
5 2016-05-01 5.00 US gdp
6 2016-02-01 1.00 US population
7 2016-03-01 2.00 US population
8 2016-04-01 3.00 US population
9 2016-05-01 4.00 US population
10 2016-06-01 5.00 US population
11 2016-02-01 2.00 US gdp per capita
12 2016-03-01 1.50 US gdp per capita
13 2016-04-01 1.33 US gdp per capita
14 2016-05-01 1.20 US gdp per capita
Есть ли простой способ сделать это в R?
2 ответа:
Да, я думаю, что проще внести изменения, которые вы хотите, с помощьюаккуратного подхода, используя
tidyr
иdplyr
.library(dplyr) library(tidyr) df <- tribble( ~date, ~value, ~country, ~indicator, "2016-01-01", 1, "US", "gdp", "2016-02-01", 2, "US", "gdp", "2016-03-01", 3, "AU", "gdp", "2016-04-01", 4, "US", "gdp", "2016-05-01", 5, "US", "gdp", "2016-02-01", 1, "US", "population", "2016-03-01", 2, "AU", "population", "2016-04-01", 3, "US", "population", "2016-05-01", 4, "US", "population", "2016-06-01", 5, "US", "population" ) df %>% group_by(country) %>% spread(indicator, value) %>% mutate(`gdp per capita` = gdp / population) %>% gather(indicator, value, -c(date, country)) %>% drop_na(value) # # A tibble: 14 x 4 # # Groups: country [2] # date country indicator value # <chr> <chr> <chr> <dbl> # 1 2016-01-01 US gdp 1.000000 # 2 2016-02-01 US gdp 2.000000 # 3 2016-03-01 AU gdp 3.000000 # 4 2016-04-01 US gdp 4.000000 # 5 2016-05-01 US gdp 5.000000 # 6 2016-02-01 US population 1.000000 # 7 2016-03-01 AU population 2.000000 # 8 2016-04-01 US population 3.000000 # 9 2016-05-01 US population 4.000000 # 10 2016-06-01 US population 5.000000 # 11 2016-02-01 US gdp per capita 2.000000 # 12 2016-03-01 AU gdp per capita 1.500000 # 13 2016-04-01 US gdp per capita 1.333333 # 14 2016-05-01 US gdp per capita 1.250000
N. B. я изменил данные и добавил оператор
group_by
, чтобы продемонстрировать решение с несколькими значениями дляcountry
.
Лично я считаю, что с пакетом reshape легче работать, и он автоматически обрабатывает наличие нескольких стран/независимо от того, сколько типов меток/типов данных у вас есть.
library(reshape) mydf <- data.frame( date=c("2016-01-01","2016-02-01","2016-03-01","2016-04-01","2016-05-01", "2016-02-01", "2016-03-01", "2016-04-01", "2016-05-01", "2016-06-01", "2016-02-01", "2016-03-01", "2016-04-01", "2016-05-01","2016-05-01"), value=c(1,2,3,4,5,1,2,3,4,5,2,1.5,1.33,1.2, 2), country=c("US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", 'AU'), indicator=c("gdp", "gdp", "gdp", "gdp", "gdp", "population", "population", "population", "population", "population", "gdp per capita", "gdp per capita", "gdp per capita", "gdp per capita", 'gdp'))
Чтобы получить новый индикатор, сначала сделайте ваши данные в широком формате так, чтобы соответствующие столбцы были рядом друг с другом. Это делается для того, чтобы вы могли выполнять простые операции с колонками
df_wide = cast(mydf, date+country~indicator, sum)
Вы хотите, чтобы страны и даты были столбцами, которые однозначно определяют строки (левая часть формулы), с differnet индикаторы в виде столбцов (правая часть формулы)
date country gdp gdp per capita population 1 2016-01-01 US 1 0.00 0 2 2016-02-01 US 2 2.00 1 3 2016-03-01 US 3 1.50 2 4 2016-04-01 US 4 1.33 3 5 2016-05-01 AU 2 0.00 0 6 2016-05-01 US 5 1.20 4 7 2016-06-01 US 0 0.00 5
Теперь сделайте новый столбец и установите его на то, что вы хотите
df_wide['g_p_ratio'] = df_wide['gdp'] / df_wide['population']
Затем используйте Melt, чтобы вернуть это в свой длинный формат
df_new = melt(df_wide, id=c('date'))
Вуаля!
date country value indicator gdp 2016-01-01 US 1.00 gdp gdp.1 2016-02-01 US 2.00 gdp gdp.2 2016-03-01 US 3.00 gdp gdp.3 2016-04-01 US 4.00 gdp gdp.4 2016-05-01 AU 2.00 gdp gdp.5 2016-05-01 US 5.00 gdp gdp.6 2016-06-01 US 0.00 gdp gdp.per.capita 2016-01-01 US 0.00 gdp per capita gdp.per.capita.1 2016-02-01 US 2.00 gdp per capita gdp.per.capita.2 2016-03-01 US 1.50 gdp per capita gdp.per.capita.3 2016-04-01 US 1.33 gdp per capita gdp.per.capita.4 2016-05-01 AU 0.00 gdp per capita gdp.per.capita.5 2016-05-01 US 1.20 gdp per capita gdp.per.capita.6 2016-06-01 US 0.00 gdp per capita population 2016-01-01 US 0.00 population population.1 2016-02-01 US 1.00 population population.2 2016-03-01 US 2.00 population population.3 2016-04-01 US 3.00 population population.4 2016-05-01 AU 0.00 population population.5 2016-05-01 US 4.00 population population.6 2016-06-01 US 5.00 population
Вы можете хотеть или не хотеть ваши новые метки строк, но вы можете исправить это
rownames(df_new) <- 1:nrow(df_new)