我有一堆名为“ haveyear”的SAS数据集,范围为2000-2018,即"have2000"-"have2018"
。它们存储在'path_to_have_data'
的本地目录中。每个数据集包含几个变量,即var1
,var2
等。我想加载这些数据集,然后根据var1 ne '0'
对其进行子集化,并且还要保留原始数据集中的var1和var2。此外,我想向每个子集添加一个新变量year
,这样我就可以确定数据来自哪一年。最后,我想将所有新的子集追加(堆叠)到名为appended
的单个数据集中。例如:
数据集Have2017
如下所示:
var1 var2 var3
0 2 5
3 7 9
数据集Have2018
如下所示:
var1 var2 var3
0 2 5
3 7 9
子集Want2017
如下所示:
var1 var2 year
3 7 2017
子集Want2018
如下所示:
var1 var2 year
3 7 2018
最终数据集appended
如下:
var1 var2 year
3 7 2017
3 7 2018
以下SAS脚本可以解决问题:
libname raw 'path_to_have_data';
%macro a;
%do &year.=2000 %to 2018;
data want&year. (keep= var1 var2);
set raw.have&year.;
where var1 ne '0';
year=&year.;
run;
%end;
%mend;
%a;
data appended;
set want:;
run;
有人知道如何用R Studio达到相同的结果吗?
这是从原始帖子中产生所需结果所需的SAS代码的工作版本。
首先,需要执行DATA步骤才能创建一些SAS数据集。我们将它们存储在默认的WORK
库中,而不是引用磁盘上的另一个库。
/* generate sample data */
data have2000 have2001 have2002;
input var1 var2 var3;
cards;
0 1 2
1 3 5
2 7 4
0 9 9
8 7 3
;
run;
接下来,我们需要对SAS宏进行一些编辑才能使其运行。
/* run macro from OP */
options mprint; /* shows SAS code generated by macro processor */
/*
* corrections / adjustments made to macro
* 1. remove & in %do loop
* 2. add year to keep list
* 3. fix syntax error in where statement because var1 is numeric
* 4. use work library, and only process 3 years of data
*/
%macro a;
%do year = 2000 %to 2002;
data want&year. (keep= var1 var2 year);
set have&year.;
where var1 ne 0;
year=&year.;
run;
%end;
%mend;
/* run the macro */
%a;
SAS选项mprint
使SAS将宏生成的代码写入日志。当我们运行宏时,为单个数据集生成的代码的子集如下所示。
MPRINT(A): data want2000 (keep= var1 var2 year);
MPRINT(A): set have2000;
MPRINT(A): where var1 ne 0;
MPRINT(A): year=2000;
MPRINT(A): run;
MPRINT(A): data want2001 (keep= var1 var2 year);
MPRINT(A): set have2001;
MPRINT(A): where var1 ne 0;
MPRINT(A): year=2001;
MPRINT(A): run;
MPRINT(A): data want2002 (keep= var1 var2 year);
MPRINT(A): set have2002;
MPRINT(A): where var1 ne 0;
MPRINT(A): year=2002;
MPRINT(A): run;
该宏生成三个SAS数据步骤,每年一次,包括以下更改。
var3
var1 = 0
want<year>
的SAS数据集最后,该代码将刚创建的数据集合并为一个名为appended
的SAS数据集。我们还将打印结果数据集。
data appended;
set want:; /* references all SAS datasets that start with "want" */
run;
proc print data = appended;
run;
...以及输出:
答案 0 :(得分:2)
这是针对该问题的Base R解决方案。 OP希望复制SAS宏的过程,该宏将SAS数据集列表raw.have2000-raw.have2018保留为两列,并设置变量year
等于数据集名称中列出的年份,并将它们合并为一个数据集。
# create some data
var1 <- 0:5
var2 <- 6:11
var3 <- 12:17
raw.have2000 <- data.frame(var1,var2,var3)
raw.have2001 <- data.frame(var1,var2,var3)
raw.have2002 <- data.frame(var1,var2,var3)
years <- 2000:2002
dataList <- lapply(years,function(x){
# create name of data set as a character object
dsname <- paste0("raw.have",x)
# use dsname with get() to extract data and subset first 2 variables
ds <- subset(get(dsname),var1 !=0,select=c(var1,var2))
ds$year <- x
# print to have data frame returned in
# output list
ds
})
# combine data frames
appended <- do.call(rbind,dataList)
...和输出,请注意已删除var1 = 0
,删除了var3
并添加了year
变量的行:
> appended
var1 var2 year
2 1 7 2000
3 2 8 2000
4 3 9 2000
5 4 10 2000
6 5 11 2000
21 1 7 2001
31 2 8 2001
41 3 9 2001
51 4 10 2001
61 5 11 2001
22 1 7 2002
32 2 8 2002
42 3 9 2002
52 4 10 2002
62 5 11 2002
>
SAS和R之间的主要区别之一是经验丰富的SAS程序员使用SAS宏语言来自动执行重复性任务。宏语言生成由SAS系统处理的SAS代码。
R没有宏语言/代码生成器。但是,可以使用get()
函数访问R对象,这些对象的名称可以通过将各种信息组合成字符对象来生成。
答案 1 :(得分:0)
考虑使用mget
将全局环境中所有需要的 have 数据帧检索到数据帧列表中。然后,对每个项目重复执行数据框操作,然后在行末绑定所有项目。
以下使用mapply
在 have 数据帧和2000-2018年之间逐元素进行迭代:
haves_dfs <- mget(ls(pattern="have"))
# SUBSET ROWS AND COLUMNS
want_dfs <- mapply(function(df, yr) transform(subset(df, var1 != '0')[c("var1", "var2")],
year = yr),
have_dfs, c(2000:2018), SIMPLIFY = FALSE)
final_df <- do.call(rbind, want_dfs)
或者使用lapply
反复使用get
:
want_dfs <- lapply(c(2000:2018), function(yr)
# SUBSET ROWS AND COLUMNS
transform(subset(get(paste0("have", yr)), var1 != '0')[c("var1", "var2")],
year = yr)
)
final_df <- do.call(rbind, want_dfs)
上面,可能看起来很密集,但是嵌套了一行
transform(subset(df, var1 != '0')[c("var1", "var2")], year = yr)
等同于多个步骤:
df_process <- function(df, yr) {
# SUBSET ROWS
df <- df[df$var1 != '0',]
# SUBSET COLUMNS
df <- df[c("var1", "var2")]
# ADD NEW COLUMN
df$year <- yr
# RETURN FINAL
return(df)
}
答案 2 :(得分:0)
感谢@Parfait也写出了能解决问题的好答案!但是,在您的第一行代码中,您编写了:
haves_dfs <- mget(ls(pattern="have"))
,随后您引用了:
have_dfs
因此,您的第一行代码应该是:
have_dfs <- mget(ls(pattern="have"))
我已经调整了您的答案,并将其与@Len给定答案的一部分的数据集结合在一起。这是该解决方案的完整示例:
var1 <- 0:5
var2 <- 6:11
var3 <- 12:17
have2000 <- data.frame(var1,var2,var3)
have2001 <- data.frame(var1,var2,var3)
have2002 <- data.frame(var1,var2,var3)
have_dfs <- mget(ls(pattern="have"))
want_dfs <- mapply(function(df, yr) transform(subset(df, var1 != '0')[c("var1", "var2")],
year = yr),
have_dfs, c(2000:2002), SIMPLIFY = FALSE)
final_df <- do.call(rbind, want_dfs)
或使用lapply
和get()
:
want_dfs <- lapply(c(2000:2002), function(yr)
transform(subset(get(paste0("have", yr)), var1 != '0')[c("var1", "var2")],
year = yr) )
final_df <- do.call(rbind, want_dfs)