使用dplyr将数据帧列重新缩放为基线条目的百分比

使用dplyr将数据帧列重新缩放为基线条目的百分比,r,dplyr,R,Dplyr,我经常需要相对于某个基线时间的值(通常为基线的百分比)重新调整时间序列。这里有一个例子 > library(dplyr) > library(magrittr) > library(tibble) > library(tidyr) # [messages from package imports snipped] > set.seed(42) > mexico <- tibble(Year=2000:2004, Country='Mexico', A=1

我经常需要相对于某个基线时间的值(通常为基线的百分比)重新调整时间序列。这里有一个例子

> library(dplyr)
> library(magrittr)
> library(tibble)
> library(tidyr)
# [messages from package imports snipped]
> set.seed(42)
> mexico <- tibble(Year=2000:2004, Country='Mexico', A=10:14+rnorm(5), B=20:24+rnorm(5))
> usa <- tibble(Year=2000:2004, Country='USA', A=30:34+rnorm(5), B=40:44+rnorm(5))
> table <- rbind(mexico, usa)
> table
# A tibble: 10 x 4
    Year Country     A     B
   <int> <chr>   <dbl> <dbl>
 1  2000 Mexico   11.4  19.9
 2  2001 Mexico   10.4  22.5
 3  2002 Mexico   12.4  21.9
 4  2003 Mexico   13.6  25.0
 5  2004 Mexico   14.4  23.9
 6  2000 USA      31.3  40.6
 7  2001 USA      33.3  40.7
 8  2002 USA      30.6  39.3
 9  2003 USA      32.7  40.6
10  2004 USA      33.9  45.3
我的第二次尝试是使用
transform
,但这失败了,因为
transform
似乎无法识别
dplyr
组,即使它起作用,也是次优的,因为它要求我知道2001年是时间序列中的第二年

> table %>%
  arrange(Country, Year) %>%
  gather(variable, value, -Year, -Country) %>%
  group_by(Country, variable) %>%
  transform(norm=value*100/value[2])
   Year Country variable    value     norm
1  2000  Mexico        A 11.37096 108.9663
2  2001  Mexico        A 10.43530 100.0000
3  2002  Mexico        A 12.36313 118.4741
4  2003  Mexico        A 13.63286 130.6418
5  2004  Mexico        A 14.40427 138.0340
6  2000     USA        A 31.30487 299.9901
7  2001     USA        A 33.28665 318.9811
8  2002     USA        A 30.61114 293.3422
9  2003     USA        A 32.72121 313.5627
10 2004     USA        A 33.86668 324.5395
11 2000  Mexico        B 19.89388 190.6402
12 2001  Mexico        B 22.51152 215.7247
13 2002  Mexico        B 21.90534 209.9157
14 2003  Mexico        B 25.01842 239.7480
15 2004  Mexico        B 23.93729 229.3876
16 2000     USA        B 40.63595 389.4085
17 2001     USA        B 40.71575 390.1732
18 2002     USA        B 39.34354 377.0235
19 2003     USA        B 40.55953 388.6762
20 2004     USA        B 45.32011 434.2961

这将是一个更好的扩展,但这里有一个简单的解决方案。你可以参考
A[Year==2001]
内的
mutate
,就像你可能在R基中做的
table$A[table$Year==2001]
一样。这让你可以根据2001年的基线或你可能需要的任何其他年份进行缩放

编辑:我丢失了一个
组_by
,以确保仅根据组中的其他值对值进行缩放。“健全性检查”(我显然没有这样做)是指2001年墨西哥的值应该有一个1的标度值,美国和其他任何国家也是如此

库(tidyverse)
种子(42)
墨西哥#西藏:10 x 6
#>#群体:国家[2]
#>年份国家A B A_基地2001 B_基地2001
#>                     
#>1 2000墨西哥11.4 19.9 1.09 0.884
#>2 2001墨西哥10.4 22.5 1
#>3 2002年墨西哥12.4 21.9 1.18 0.973
#>4 2003年墨西哥13.6 25.0 1.31 1.11
#>5 2004年墨西哥14.4 23.9 1.38 1.06
#>6 2000美国31.3 40.6 0.940 0.998
#>7 2001美国33.3 40.7 1
#>8 2002美国30.6 39.3 0.920 0.966
#>9 2003美国32.7 40.6 0.983 0.996
#>10 2004美国33.9 45.3 1.02 1.11

由(v0.2.0)于2018年5月23日创建。

受卡米尔答案的启发,我发现了一种简单的方法,可以很好地扩展:

table %>%
  gather(variable, value, -Year, -Country) %>%
  group_by(Country, variable) %>%
  mutate(value=100*value/value[Year == 2001]) %>%
  spread(variable, value)
# A tibble: 10 x 4
# Groups:   Country [2]
    Year Country     A     B
   <int> <chr>   <dbl> <dbl>
 1  2000 Mexico  109.   88.4
 2  2000 USA      94.0  99.8
 3  2001 Mexico  100.  100
 4  2001 USA     100   100
 5  2002 Mexico  118.   97.3
 6  2002 USA      92.0  96.6
 7  2003 Mexico  131.  111.
 8  2003 USA      98.3  99.6
 9  2004 Mexico  138.  106.
10  2004 USA     102.  111.
第二种等效方法是创建一个新表,其中列按比例“就地”缩放,然后将其与原始表合并

table %>% 
  gather(variable, value, -Year, -Country) %>%
  group_by(Country, variable) %>%
  mutate(value=100*value/value[Year == 2001]) %>%
  ungroup() %>%
  mutate(variable=paste(variable, 'scaled', sep='_')) %>% 
  spread(variable, value) %>%
  inner_join(table)
Joining, by = c("Year", "Country")
# A tibble: 10 x 6
    Year Country A_scaled B_scaled     A     B
   <int> <chr>      <dbl>    <dbl> <dbl> <dbl>
 1  2000 Mexico     109.      88.4  11.4  19.9
 2  2000 USA         94.0     99.8  31.3  40.6
 3  2001 Mexico     100.     100    10.4  22.5
 4  2001 USA        100      100    33.3  40.7
 5  2002 Mexico     118.      97.3  12.4  21.9
 6  2002 USA         92.0     96.6  30.6  39.3
 7  2003 Mexico     131.     111.   13.6  25.0
 8  2003 USA         98.3     99.6  32.7  40.6
 9  2004 Mexico     138.     106.   14.4  23.9
10  2004 USA        102.     111.   33.9  45.3
表%>%
聚集(变量、值、-年、-国家)%>%
集团单位(国家,变量)%>%
变异(值=100*值/值[年==2001])%>%
解组()%>%
变异(变量=粘贴(变量,'缩放',sep='')%>%
价差(变量、值)%>%
内螺纹联接(表)
加入,由=c(“年度”、“国家”)
#一个tibble:10x6
年份国家A_标B_标A B
1 2000年墨西哥109。88.4  11.4  19.9
2 2000美国94.0 99.8 31.3 40.6
3 2001年墨西哥100。100    10.4  22.5
4 2001美国100 100 33.3 40.7
5 2002年墨西哥118。97.3  12.4  21.9
6 2002美国92.0 96.6 30.6 39.3
7 2003年墨西哥131。11113.6  25.0
8 2003美国98.3 99.6 32.7 40.6
9 2004年墨西哥138。10614.4  23.9
10 2004年美国102。11133.9  45.3

可以将最终的
内部联接
替换为
排列(县,年)%%>%select(-Country,-Year)%%>%bind\u cols(表)
,这可能对某些数据集的性能更好,尽管它对列的排序不太理想。

A_base2001
B_base2001
下的
2001
条目不应该都是
1
?我认为问题在于两个基线向量的长度(例如
c(10.4,33.3)
对于
A
)按照给定的顺序循环使用
A
:墨西哥2000对墨西哥基线,墨西哥2001对美国基线,然后墨西哥2002对墨西哥基线,等等。添加一个
arrange(year)
通过对齐几对年份条目来解决这个问题,但是如果缺少任何年份/国家组合(实际数据中经常出现),那么它也很脆弱。老实说,这是一个足够常见的问题,值得编写一个
dplyr
扩展包来解决吗?@ConnorHarris yes,我不知道我怎么会错过那个!通过添加一个
group\u可以解决这一问题,因此墨西哥的价值观只会相互对比,美国也是如此。我现在正在解决这一问题。@ConnorHarris至少在我的工作领域,即分析人口统计和其他普查数据,这是一项非常常见的任务,通常需要我进行大量的
收集
/
传播
争论。实际上,我现在正在编写一个软件包,使用一个函数来简化和扩展这个过程。我想我找到了一种不需要指定列名的工作方法。
table %>%
  gather(variable, original, -Year, -Country) %>%
  group_by(Country, variable) %>%
  mutate(scaled=100*original/original[Year == 2001]) %>%
  gather(scaled, value, -Year, -Country, -variable) %>% 
  unite(variable_scaled, variable, scaled, sep='_') %>% 
  mutate(variable_scaled=gsub("_original", "", variable_scaled)) %>% 
  spread(variable_scaled, value)
# A tibble: 10 x 6
# Groups:   Country [2]
    Year Country     A A_scaled     B B_scaled
   <int> <chr>   <dbl>    <dbl> <dbl>    <dbl>
 1  2000 Mexico   11.4    109.   19.9     88.4
 2  2000 USA      31.3     94.0  40.6     99.8
 3  2001 Mexico   10.4    100.   22.5    100
 4  2001 USA      33.3    100    40.7    100
 5  2002 Mexico   12.4    118.   21.9     97.3
 6  2002 USA      30.6     92.0  39.3     96.6
 7  2003 Mexico   13.6    131.   25.0    111.
 8  2003 USA      32.7     98.3  40.6     99.6
 9  2004 Mexico   14.4    138.   23.9    106.
10  2004 USA      33.9    102.   45.3    111.
table %>% 
  gather(variable, value, -Year, -Country) %>%
  group_by(Country, variable) %>%
  mutate(value=100*value/value[Year == 2001]) %>%
  ungroup() %>%
  mutate(variable=paste(variable, 'scaled', sep='_')) %>% 
  spread(variable, value) %>%
  inner_join(table)
Joining, by = c("Year", "Country")
# A tibble: 10 x 6
    Year Country A_scaled B_scaled     A     B
   <int> <chr>      <dbl>    <dbl> <dbl> <dbl>
 1  2000 Mexico     109.      88.4  11.4  19.9
 2  2000 USA         94.0     99.8  31.3  40.6
 3  2001 Mexico     100.     100    10.4  22.5
 4  2001 USA        100      100    33.3  40.7
 5  2002 Mexico     118.      97.3  12.4  21.9
 6  2002 USA         92.0     96.6  30.6  39.3
 7  2003 Mexico     131.     111.   13.6  25.0
 8  2003 USA         98.3     99.6  32.7  40.6
 9  2004 Mexico     138.     106.   14.4  23.9
10  2004 USA        102.     111.   33.9  45.3