【问题标题】:Referring to objects using variable strings in R在 R 中使用变量字符串引用对象
【发布时间】:2012-05-22 05:07:29
【问题描述】:

编辑:感谢迄今为止做出回应的人;我是 R 的初学者,刚刚为我的理学硕士论文承担了一个大型项目,所以对初始处理有点不知所措。我使用的数据如下(来自 WMO 公开的降雨数据):


120 6272100 KHARTOUM 15.60 32.55 382 1899 1989 0.0
1899 0.03 0.03 0.03 0.03 0.03 1.03 13.03 12.03 9999 6.03 0.03 0.03
1900 0.03 0.03 0.03 0.03 0.03 23.03 80.03 47.03 23.03 8.03 0.03 0.03
1901 0.03 0.03 0.03 0.03 0.03 17.03 23.03 17.03 0.03 8.03 0.03 0.03
(...)
120 6272101 JEBEL AULIA 15.20 32.50 380 1920 1988 0.0
1920 0.03 0.03 0.03 0.00 0.03 6.90 20.00 108.80 47.30 1.00 0.01 0.03
1921 0.03 0.03 0.03 0.00 0.03 0.00 88.00 57.00 35.00 18.50 0.01 0.03
1922 0.03 0.03 0.03 0.00 0.03 0.00 87.50 102.30 10.40 15.20 0.01 0.03
(...)

我对大约 100 个观测站感兴趣,每个观测站都有不同的降雨测量开始和结束日期。它们在单个数据文件中采用上述格式,各站之间用“120(站号)(站名)”分隔。

我需要先将这个文件按站分开,然后提取每年的三月、四月、五月和六月,然后将每年的这些月份合计起来。到目前为止,我一直在搞乱循环(如下所示),但我知道这不是正确的方法,我宁愿学习一些更好的技术。 再次感谢您的帮助!

(原问题:) 我有一个大型数据集,其中包含 100 多个地点的约 100 年按季节划分的降雨量。我正在尝试将这些数据分成更易于管理的数组,特别是我想检索每年每个站点的 3 月、4 月、5 月和 6 月的降雨量总和。 以下是到目前为止我的代码的简化版本:

a <- array(1,dim=c(10,12))
for (i in 1:5) {

  all data:
  assign(paste("station_",i,sep=""), a)

  #march - june data:
  assign(paste("station_",i,"_mamj",sep=""), a[,4:7])
}

所以这给了我station_(i)__mamj_,其中包含我对每个电台感兴趣的月份的数据。现在我想对这个数组的每一行求和,并将其输入一个名为station_(i)_mamj_tot 的新数组中。理论上很简单,但我不知道如何引用 station_(i)_mamj 以便它在每次迭代时改变 i 的值。非常感谢任何帮助!

【问题讨论】:

  • 这不是一个可重复的示例,因为您没有提供任何数据。我建议您查看此LINK 以制作可重现的示例。
  • 如前所述,您可能真的应该使用列表来解决这个问题。如果我们知道您的数据是什么样的,我们可能会为您提供更多帮助。例如,从我可以收集到的内容中,使用splitlapply 可能会更干净地完成您想要做的事情。
  • 如果您可以以每列代表特定年份的一个月的方式制作数据框,那么您可以使用summary(data.frame)得到总和
  • @Subs,他想按年份汇总,但只计算 mamj 总数。这是Split-Apply-Combine的工作!请参阅下面的 ddply 单线!
  • OP,只要你可以矢量化,就避免使用循环,这就是 R 的力量。在你的允许下,我想从 'variables','loops','concatenation'重新标记> 到 'vectorization','loops','plyr'?

标签: string r variables loops concatenation


【解决方案1】:

为什么要使用assign 来创建station1station2station_3_mamj 等变量?将它们存储在列表中会更容易、更直观,例如stations[[1]]stations[[2]]stations_mamj[[3]] 等。然后可以使用它们的索引来访问每个。

由于您正在处理的每个站点数据看起来都是一个大小相同的矩阵,您甚至可以将它们作为一个 3 维矩阵来处理。

ETA:顺便说一句,如果你真的想用这种方式解决问题,你会这样做:

eval(parse(text=paste("station", i, "mamj", sep="_")))

但不要 - 使用 eval 几乎总是不好的做法,并且会使对您的数据进行甚至简单的操作都变得困难。

【讨论】:

    【解决方案2】:

    对于您的原始问题,请使用 get():

    i <- 10
    var <- paste("test", i, sep="_")
    assign(10, var)
    get(var)
    

    正如 David 所说,这可能不是最好的选择,但它有时会很有用(而且 IMO 的 assign/get 构造比 eval(parse) 好得多)

    【讨论】:

    • 对于get 为真。但是,当您所做的只是为每个索引保存一个变量时,不使用列表和矩阵等内置类型是非常愚蠢的。
    • 因此“正如大卫所说,这可能不是最好的选择”:)
    • data.frame 比数组的优势在于我们可以使用异构列,因此我们可以将“年”和“月”列作为因子......然后我们可以任意拆分应用-按年、月或其任意子集组合。而数组对于数据分析来说确实非常有限。
    • 问题是他(最初)问的是如何从任意变量名中获取值,而不是他应该如何构造他的问题。正如我在帖子中所说,很明显他没有以正确的方式做事(参见 Lumley 的 fortune() 关于 eval(parse()) 的俏皮话)。用 data.frames 等回答(原始)Q 实际上并不能回答(原始)Q。
    【解决方案3】:

    这完全是在乞求一个数据框,然后它只是一个带有像ddply 这样的电动工具的单行字(非常强大):

    tot_mamj <- ddply(rain[rain$month %in% 3:6,-2], 'year', colwise(sum))
    

    按年份给出 M/A/M/J 的总和:

       year station_1 station_2 station_3 station_4 station_5 ...
    1  1972  8.618960  5.697739 10.083192  9.264512 11.152378 ...
    2  1973 18.571748 18.903280 11.832462 18.262272 10.509621 ...
    3  1974 22.415201 22.670821 32.850745 31.634717 20.523778 ...
    4  1975 16.773286 17.683704 18.259066 14.996550 19.007762 ...
    ...
    

    以下是完美运行的代码。我们创建一个 col.names 为 'station_n' 的数据框;年和月的额外列(因子,或者如果你很懒,则为整数,请参见脚注)。现在您可以按月或按年进行任意分析(使用 plyr 的 split-apply-combine 范例):

    require(plyr) # for d*ply, summarise
    #require(reshape) # for melt
    
    # Parameterize everything here, it's crucial for testing/debugging
    all_years <- c(1970:2011)
    nYears <- length(all_years)  
    nStations <- 101
    # We want station names as vector of chr (as opposed to simple indices)
    station_names <- paste ('station_', 1:nStations, sep='')
    
    rain <- data.frame(cbind(
      year=rep(c(1970:2011),12),
      month=1:12
    ))
    # Fill in NAs for all data
    rain[,station_names] <- as.numeric(NA)
    # Make 'month' a factor, to prevent any numerical funny stuff e.g accidentally 'aggregating' it
    rain$month <- factor(rain$month)
    
    # For convenience, store the row indices for all years, M/A/M/J
    I.mamj <- which(rain$month %in% 3:6)
    
    # Insert made-up seasonal data for M/A/M/J for testing... leave everything else NA intentionally
    rain[I.mamj,station_names] <- c(3,5,9,6) * runif(4*nYears*nStations)
    
    # Get our aggregate of MAMJ totals, by year
    # The '-2' column index means: "exclude month, to prevent it also getting 'aggregated'"
    excludeMonthCol = -2
    tot_mamj <- ddply(rain[rain$month %in% 3:6, excludeMonthCol], 'year', colwise(sum))
    
    # voila!!
    #    year station_1 station_2 station_3 station_4 station_5
    # 1  1972  8.618960  5.697739 10.083192  9.264512 11.152378
    # 2  1973 18.571748 18.903280 11.832462 18.262272 10.509621
    # 3  1974 22.415201 22.670821 32.850745 31.634717 20.523778
    # 4  1975 16.773286 17.683704 18.259066 14.996550 19.007762
    

    作为脚注,在我将月份从数字转换为因子之前,它正在默默地“聚合”(直到我输入“-2”:排除列引用)。 然而,更好的是当你把它作为一个因素时,它会拒绝直接聚合,并抛出一个错误(这对于调试来说是可取的):

     ddply(rain[rain$month %in% 3:6, ], 'year', colwise(sum))
    Error in Summary.factor(c(3L, 3L, 3L, 3L, 3L, 3L), na.rm = FALSE) : 
      sum not meaningful for factors
    

    【讨论】:

      猜你喜欢
      • 2011-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      • 2017-11-16
      • 2013-10-08
      • 1970-01-01
      相关资源
      最近更新 更多