在R中使用变量字符串引用对象

3

编辑:感谢那些已经回复的人;我在R语言方面是个初学者,现在接了一个MSc论文的大项目,初始处理有点不知所措。我使用的数据如下(来自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(站点编号)(站点名称)"分隔。

我首先需要将此文件按站点分开,然后提取每年的3月、4月、5月和6月的数据,然后计算这些月份的总和。目前我正在使用循环(如下所示),但我知道这不是正确的方法,而且我更想学习一些更好的技术。再次感谢您的帮助!

(原始问题:) 我有一个包含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的值。非常感谢任何帮助!


2
这不是一个可重现的例子,因为您没有提供任何数据。我建议您查看这个链接,了解如何创建可重现的例子。 - Tyler Rinker
如果您可以以每列代表特定年份的月份的方式创建数据框,则可以使用 summary(data.frame) 轻松获取总和。 - Subs
OP,尽可能矢量化避免使用循环,这就是 R 的优势。如果您同意,我想将标签从“variables”,“loops”,“concatenation”更改为“vectorization”,“loops”,“plyr”。 - smci
大家好,感谢迄今为止的帮助;你们可能已经猜到我对R(以及编程)还很陌生!如有必要,请随意重新标记 - 我只是在努力获取一些可用的数据,以便让您看到我实际想要实现什么,很快会编辑帖子。 - Ruari Rhodes
@OP 你可能没有注意到,但是5天前我给出了一个回答,不仅回答了你问题的本质,而且在ddply一行代码中超出了1000%,解决了你整个的问题,并提供了许多基于我的经验教训的小提示,如何适应R习惯用法、split-apply-combine,如何正确使用NAs等等...所有这些花费了我2个小时的编码、研究和验证...你有注意到吗? - smci
显示剩余3条评论
3个回答

4

这完全需要一个dataframe,然后就像这个一行代码那样使用强大的工具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 ...
...

以下是可以正常工作的代码。我们创建了一个数据框,其列名为'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

2

针对您的原始问题,请使用get()方法:

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

正如David所说,这可能不是最好的方法,但有时它也可以很有用(并且在我看来,赋值/获取结构比eval(parse)要好得多)


关于 get,这是正确的。然而,当你只需要保存每个索引一个变量时,不使用内置类型如列表和矩阵非常愚蠢。 - David Robinson
因此,“正如David所说,这可能不是最好的选择。” :) - geoffjentry
data.framearray更有优势,因为我们可以使用不同类型的列,所以我们可以将“年份”和“月份”都作为因子变量的列添加到数据框中...然后我们可以通过年份、月份或者其中任意一个子集进行任意划分-应用-合并操作。而数组在数据分析方面非常有限。 - smci
问题在于他最初询问如何从任意变量名称中获取值,而不是他应该如何构建他的问题。正如我在帖子中所述,很明显他没有正确处理事情(请参见Lumley关于eval(parse())的fortune()警句)。用数据框等回答(原始)Q实际上并没有回答(原始)Q。 - geoffjentry

1

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

由于看起来你正在处理的每个站点数据都是相同大小的矩阵,甚至可以将它们视为三维矩阵进行处理。

补充说明:顺便说一句,如果您真的想用这种方法解决问题,可以这样做:

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

但是不要使用eval,这几乎总是不好的做法,会使您难以对数据执行甚至简单的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接