【问题标题】:Conditionally multiplying vectors (currency conversion)条件乘法向量(货币换算)
【发布时间】:2015-05-23 20:50:57
【问题描述】:

我有一个相当大的数据框,其中变量以当地年度货币(在下面的示例中为澳大利亚和奥地利货币)计价:

 Country   Var  _1995       _1996         _1997      _1998
     AUS    GO  1 014 828   1 059 326     1 119 101  1 194 995
     AUS    L   36 873      38 895        39 502     40 425
     AUS    K   41 498      45 008        48 683     47 252
     AUT    GO  289 923     299 487       309 734    323 273
     AUT    GO  8 032       7 849         8 049      7 815
     AUT    L   1 094       1 151         1 163      1 152
     AUT    K   12 032      11 760        11 743     11 611

我想使用以下乘数将此数据框中的值转换为 1995 美元:

Country   _1995     _1996     _1997  _1998 
AUS      0,7415   0,78295   0,74406  0,6294
AUT     1,36646   1,30031   1,12904 1,11319

因此,对于表 1 中包含变量 AUS 的每一行,每年的值乘以表 2 中包含 AUS 的行的适当的 $1995 乘数。同样的情况也适用于包含 AUT 的每一行作为我数据框中的其他 38 个国家/地区代码。

所以,在第一行我希望 R 执行这个计算:

 Country Var    _1995            _1996            _1997           _1998        
    AUS  GO  1014828*0,7415 1059326*0,78295   1119101*0,74406 1194995*0,6294 

等等。这是可行的吗?非常感谢您的帮助!

【问题讨论】:

  • 您能否使用dput 提供两个示例数据集?
  • 也许 merge(dataset, converttable, by="country") 可能会有所帮助,然后将每一年的列相乘。

标签: r vector conditional currency


【解决方案1】:

我建议将宽格式改成长格式,这将大大简化此操作。重塑是最复杂的部分。我在这里使用示例数据和reshape 命令展示它,但您也可以使用dplyr 或reshape2 或其他。

基本上,将两个数据集重新整形为长,然后合并它们,执行乘法(在长格式中,只是简单的向量乘法),然后重新整形为宽。

这是示例数据(与您的类似):

set.seed(1)
dat <- data.frame(Country = rep(c("AUS", "AUT"), each = 3), 
                  Var = rep(c("GO", "L", "K"), times = 2), 
                  v_1996 = rnorm(6), v_1997 = rnorm(6), v_1998 = rnorm(6),  
                  stringsAsFactors = FALSE)

multipliers <- data.frame(Country = c("AUS", "AUT"), 
                          v_1995 = c(0.7415, 1.36646),
                          v_1996 = c(0.78295, 1.30031),
                          v_1997 = c(0.74406, 1.12904),
                          v_1998 = c(0.6294, 1.11319), stringsAsFactors = FALSE)

这是进行转换的代码:

long <- reshape(dat, times = 1996:1998, v.names = "Value", 
                varying = c("v_1996", "v_1997", "v_1998"), 
                direction = "long")
head(long, 3)
#        Country Var time      Value id
# 1.1996     AUS  GO 1996 -0.6264538  1
# 2.1996     AUS   L 1996  0.1836433  2
# 3.1996     AUS   K 1996 -0.8356286  3
# 4.1996     AUT  GO 1996  1.5952808  4

mlong <- reshape(multipliers, times = 1995:1998, v.names = "mult", 
                 varying = c("v_1995","v_1996", "v_1997", "v_1998"), 
                 direction = "long")
head(mlong, 3)
#        Country time    mult id
# 1.1995     AUS 1995 0.74150  1
# 2.1995     AUT 1995 1.36646  2
# 1.1996     AUS 1996 0.78295  1

merged <- merge(long, mlong, by = c("Country", "time"))
merged$converted <- merged$Value * merged$mult    
head(merged, 3)
#   Country time Var      Value id.x    mult id.y  converted
# 1     AUS 1996  GO -0.6264538    1 0.78295    1 -0.4904820
# 2     AUS 1996   L  0.1836433    2 0.78295    1  0.1437835
# 3     AUS 1996   K -0.8356286    3 0.78295    1 -0.6542554

reshape(merged, idvar = c("Country", "Var"), direction = "wide", 
        drop = c("id.x", "id.y","mult"))
#    Country Var Value.1996 converted.1996 Value.1997 converted.1997  Value.1998 converted.1998
# 1      AUS  GO -0.6264538     -0.4904820  0.4874291      0.3626765 -0.62124058    -0.39100882
# 2      AUS   L  0.1836433      0.1437835  0.7383247      0.5493579 -2.21469989    -1.39393211
# 3      AUS   K -0.8356286     -0.6542554  0.5757814      0.4284159  1.12493092     0.70803152
# 10     AUT  GO  1.5952808      2.0743596 -0.3053884     -0.3447957 -0.04493361    -0.05001964
# 11     AUT   L  0.3295078      0.4284623  1.5117812      1.7068614 -0.01619026    -0.01802284
# 12     AUT   K -0.8204684     -1.0668632  0.3898432      0.4401486  0.94383621     1.05066903

【讨论】:

  • 谢谢。尝试了你的解决方案,虽然我在 reshape 包中使用了 melt 功能,而不是你这样做的方式。
  • 谢谢。尝试了您的解决方案,尽管我使用了“重塑”中的融化功能,而不是您使用的方式。它工作正常,直到我到达“merged$converted
  • 检查您要相乘的变量的class()。该错误意味着其中一个属于“因素”类。您可能需要通过 as.numeric(as.character(variable)) 之类的方式将变量类修改为数字。
  • 是的。我的数据似乎有问题(即某些单元格中的非数字字符)。您的解决方案对于未入门的人来说既简单又明显,而且我已经将一些修改后的代码用于其他操作。再次感谢!
【解决方案2】:

类似这样的:

(假设您的本地货币数据框称为“local”,而带有乘数的数据框称为“conv”。)

#unfactorise Country or you'll get very strange results
local$Country <- as.character(local$Country); conv$Country <- as.character(conv$Country)
countries <- unique(local$Country)
for(i in 1:length(countries)) {
        cy <- countries[i]
        rates <- matrix(conv[conv$Country==cy, -1])
        local[local$Country==cy, -c(1,2)] <- local[local$Country==cy, -c(1,2)] * rates
}

【讨论】:

    【解决方案3】:

    创建一个小辅助函数然后通过管道传输数据可能是最简单的。为了使其更简洁,请将转化的 row.names 设置为 Country 并删除该列。

    df <- read.table(header = TRUE, text = '
                     Country Var  _1995       _1996         _1997      _1998
         AUS   GO  1014828   1059326     1119101  1194995
         AUS   L   36873      38895        39502     40425
         AUS   K    41498     45008        48683     47252
         AUT   GO  289923     299487       309734    323273
         AUT   GO  8032       7849         8049      7815
         AUT   L   1094       1151         1163      1152
         AUT   K   12032      11760        11743     11611
                     ')
    
    conversions <- read.table(header = TRUE, text='
                              Country _1995     _1996   _1997   _1998 
     AUS     0.7415    0.78295 0.74406 0.6294
     AUT     1.36646   1.30031 1.12904 1.11319
                              ')
    
    # the primary code to use
    # set row.names, makes indexing cleaner below
    row.names(conversions) <- conversions$Country
    conversions <- conversions[,-1]
    
    # helper function for conversions
    myfun <- function(df1, df2) {
        df1[,3:6] <- df1[,3:6] * df2[df1$Country,]
        df1
    }
    
    library(dplyr)
    df %>% 
       group_by(Country) %>% 
       do(myfun(., conversions))
    
    Source: local data frame [7 x 6]
    Groups: Country
    
      Country Var     X_1995     X_1996     X_1997     X_1998
    1     AUS  GO 752494.962 829399.292 832678.290 752129.853
    2     AUS   L  27341.330  30452.840  29391.858  25443.495
    3     AUS   K  30770.767  35239.014  36223.073  29740.409
    4     AUT  GO 396168.183 389425.941 349702.075 359864.271
    5     AUT  GO  10975.407  10206.133   9087.643   8699.580
    6     AUT   L   1494.907   1496.657   1313.074   1282.395
    7     AUT   K  16441.247  15291.646  13258.317  12925.249
    

    【讨论】:

      【解决方案4】:

      这是我使用dplyr 的尝试。我正在以各种方式进行实验并想出了这个。我首先将数据(即mydf)拆分为Country。对于列表中的每个数据框,我想应用适当的汇率。因此,我使用Country 对汇率数据(即rate)进行了子集化并创建了新数据。 (当代码运行时,R 正在获取每个国家/地区的汇率。)我在this question 中应用了我的答案,以便使用mutate_each() 计算多个列。最后我用bind_rows()把所有的数据框组合起来。

      lapply(split(mydf, mydf$Country), function(i) {
      
              foo <- rate[rate$Country == unique(i$Country),]
      
              mutate_each(i, funs(. * foo$.), y_1995:y_1998)
      
          }) %>%
      bind_rows
      
      #  Country Var     y_1995     y_1996     y_1997     y_1998
      #1     AUS  GO 752494.962 829399.292 832678.290 752129.853
      #2     AUS   L  27341.330  30452.840  29391.858  25443.495
      #3     AUS   K  30770.767  35239.014  36223.073  29740.409
      #4     AUT  GO 396168.183 389425.941 349702.075 359864.271
      #5     AUT  GO  10975.407  10206.133   9087.643   8699.580
      #6     AUT   L   1494.907   1496.657   1313.074   1282.395
      #7     AUT   K  16441.247  15291.646  13258.317  12925.249
      

      数据

      mydf <- structure(list(Country = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 
      2L), .Label = c("AUS", "AUT"), class = "factor"), Var = structure(c(1L, 
      3L, 2L, 1L, 1L, 3L, 2L), .Label = c("GO", "K", "L"), class = "factor"), 
      y_1995 = c(1014828, 36873, 41498, 289923, 8032, 1094, 12032
      ), y_1996 = c(1059326, 38895, 45008, 299487, 7849, 1151, 
      11760), y_1997 = c(1119101, 39502, 48683, 309734, 8049, 1163, 
      11743), y_1998 = c(1194995, 40425, 47252, 323273, 7815, 1152, 
      11611)), .Names = c("Country", "Var", "y_1995", "y_1996", 
      "y_1997", "y_1998"), row.names = c(NA, -7L), class = "data.frame")
      
      #  Country Var  y_1995  y_1996  y_1997  y_1998
      #1     AUS  GO 1014828 1059326 1119101 1194995
      #2     AUS   L   36873   38895   39502   40425
      #3     AUS   K   41498   45008   48683   47252
      #4     AUT  GO  289923  299487  309734  323273
      #5     AUT  GO    8032    7849    8049    7815
      #6     AUT   L    1094    1151    1163    1152
      #7     AUT   K   12032   11760   11743   11611
      
      rate <- structure(list(Country = structure(1:2, .Label = c("AUS", "AUT"
      ), class = "factor"), y_1995 = c(0.7415, 1.36646), y_1996 = c(0.78295, 
      1.30031), y_1997 = c(0.74406, 1.12904), y_1998 = c(0.6294, 1.11319
      )), .Names = c("Country", "y_1995", "y_1996", "y_1997", "y_1998"
      ), row.names = c(NA, -2L), class = "data.frame")
      
      #  Country  y_1995  y_1996  y_1997  y_1998
      #1     AUS 0.74150 0.78295 0.74406 0.62940
      #2     AUT 1.36646 1.30031 1.12904 1.11319
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-03-15
        • 2021-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-29
        相关资源
        最近更新 更多