R "for loop" and/or 应用于动态变换多个变量
R "for loop" and/or Apply to transform several variables dynamically
我正在尝试 translate/replicate 将我在 EViews 中使用的 shorthand "for loop" 技术融入 R。我正在尝试复制一个 "for loop" ,我会将一个时间序列变量除以另一个(向量)并将其保存为一个新序列。
由于我使用通用命名约定(例如 GDP(实际)、GDPn(名义)和 GDP_P(价格),请参见下面的 EViews 示例),我可以声明变量列表一次并使用更改后缀("n" 或“_P”)以创建动态系列名称并循环执行我需要的计算。我的输入数据是国民账户支出系列。
'EViews shorthand "for next" loop:
%CATS = "GDP CONS INV GOV EX IM"
for %CATS {%cats}
series {%cats}_P= {%cats}n / {%cats}
next
'Which is shorthand replication of below ("series" declares a series of the subsequent name):
series GDP_P = GDPn / GDP
series CONS_P = CONSn / CONS
series INV_P = INVn / INV
series GOV_P = GOVn / GOV
series EX_P = EXn / EX
series IM_P = IMn / IM
到目前为止,我已经尝试使用 R for 循环(我读过这不是 R 中的首选方法),方法是创建系列名称的向量并使用 "assign(paste" 进行计算。下面是一个示例,但它不起作用。根据我对 "for" 命令的了解,"i" 的声明系列只能是值向量或名称向量,没有进一步的上下文:
cats<-c("GDP","CONS","GOV","INV","EX","IM")
for (i in cats){
assign(paste(i, "_P",sep=""), paste(i, "n",sep="")/i)
}
我也对 "apply" 函数和派生函数进行了大量阅读,但我看不出它在上述情况下是如何工作的。关于如何在 R 中执行此操作的任何建议都会有所帮助。
你的函数应该像这样工作:
cats<-c("GDP","CONS","GOV","INV","EX","IM")
for (i in cats){
assign(paste(i, "_P",sep=""), get(paste(i, "n",sep=""))/get(i))
}
get
将使用您提供的字符串并找到该名称的向量。
还有一种非 for 循环的方法,使用其中一个答案的想法 here:
txt<-paste0(cats, "_P <- ", cats, "n/", cats)
eval(parse(text=txt))
txt
将包含您必须键入以手动创建所有向量的所有行的列表,然后 eval(parse(text=txt))
获取这些命令中的每一个并逐条执行它们.
您当然可以跳过将文本分配给 txt
-- 我只是想让它更清楚这里发生了什么:
eval(parse(text=paste0(cats, "_P <- ", cats, "n/", cats)))
考虑使用列表,尤其是对于许多相似的元素。这样做,您可以更好地管理您的全球环境并更紧凑、更高效地处理数据。对您来说,这意味着维护 3 个向量列表而不是 18 个单独的命名向量(2 个原始集和新的第 3 个集)。使用 assign
动态创建变量通常表示有机会使用命名列表。
具体来说,在 GDPn_list 和 GDP_list 中收集你的物品,然后使用 Map
(mapply
的非简化包装器)在调用除法函数 /
的两个等长列表之间逐元素迭代。然后用 setNames()
命名列表。下面使用随机数据进行演示,但对于您来说,OP 可以使用注释掉的行来构建列表。
原始数据
cats <- c("GDP","CONS","GOV","INV","EX","IM")
set.seed(9272018)
GDPn_list <- setNames(replicate(6, runif(50)*120, simplify=FALSE), paste0(cats, "n"))
# GDPn_list <- list(GDPn, CONSn, GOVn, INVn, EXn, IMn)
str(GDPn_list)
# List of 6
# $ GDPn : num [1:50] 52.4 31.9 10.6 118.4 66 ...
# $ CONSn: num [1:50] 18.27 22.3 95.13 87.44 9.79 ...
# $ GOVn : num [1:50] 48.83 69.73 113.61 35.53 1.21 ...
# $ INVn : num [1:50] 51.9 96.9 28.2 67.2 19 ...
# $ EXn : num [1:50] 28.3 94.3 42.3 65.5 83.6 ...
# $ IMn : num [1:50] 109.3 26.6 60.2 78.2 55.5 ...
GDP_list <- setNames(replicate(6, runif(50)*100, simplify=FALSE), cats)
# GDPn_list <- list(GDP, CONS, GOV, INV, EX, IM)
str(GDP_list)
# List of 6
# $ GDP : num [1:50] 51.1 65.9 41.5 24.5 87.3 ...
# $ CONS: num [1:50] 47.66 77.32 46.97 48.61 2.98 ...
# $ GOV : num [1:50] 32.6 70.3 21.5 73.4 97.8 ...
# $ INV : num [1:50] 80.7 16.8 57.4 80.7 12.1 ...
# $ EX : num [1:50] 38.1 78.1 40.6 62.8 61.9 ...
# $ IM : num [1:50] 39.8 84.8 11.4 39.7 14.7 ...
新数据
GDPp_list <- setNames(Map(`/`, GDPn_list, GDP_list), paste0(cats, "p"))
str(GDPp_list)
# List of 6
# $ GDPp : num [1:50] 1.025 0.484 0.256 4.835 0.756 ...
# $ CONSp: num [1:50] 0.383 0.288 2.025 1.799 3.286 ...
# $ GOVp : num [1:50] 1.4969 0.9921 5.2891 0.4844 0.0124 ...
# $ INVp : num [1:50] 0.644 5.775 0.491 0.832 1.578 ...
# $ EXp : num [1:50] 0.744 1.207 1.043 1.043 1.352 ...
# $ IMp : num [1:50] 2.747 0.314 5.293 1.971 3.783 ...
而且您仍然可以通过名称或索引号引用您的基础数字向量,而不会丢失任何功能或数据:
GDPp_list$GDPp
GDPp_list$CONSp
GDPp_list$GOVp
...
GDPp_list[[1]]
GDPp_list[[2]]
GDPp_list[[3]]
...
如果是等长向量,则根据您的列表构建一个矩阵!这次使用 mapply
:
GDPp_matrix <- mapply(`/`, GDPn_list, GDP_list)
colnames(GDPp_matrix) <- paste0(cats, "p")
head(GDPp_matrix)
# GDPp CONSp GOVp INVp EXp IMp
# [1,] 1.0252871 0.3832836 1.49687150 0.6436575 0.7441159 2.746551
# [2,] 0.4835700 0.2884577 0.99208666 5.7753575 1.2067694 0.314102
# [3,] 0.2562130 2.0251752 5.28913247 0.4910816 1.0429316 5.292843
# [4,] 4.8345697 1.7987625 0.48436284 0.8322211 1.0431301 1.970523
# [5,] 0.7563794 3.2859395 0.01236608 1.5781949 1.3518592 3.783420
# [6,] 0.1515318 10.9332338 1.10608066 13.7953500 0.7211371 1.918249
我正在尝试 translate/replicate 将我在 EViews 中使用的 shorthand "for loop" 技术融入 R。我正在尝试复制一个 "for loop" ,我会将一个时间序列变量除以另一个(向量)并将其保存为一个新序列。
由于我使用通用命名约定(例如 GDP(实际)、GDPn(名义)和 GDP_P(价格),请参见下面的 EViews 示例),我可以声明变量列表一次并使用更改后缀("n" 或“_P”)以创建动态系列名称并循环执行我需要的计算。我的输入数据是国民账户支出系列。
'EViews shorthand "for next" loop:
%CATS = "GDP CONS INV GOV EX IM"
for %CATS {%cats}
series {%cats}_P= {%cats}n / {%cats}
next
'Which is shorthand replication of below ("series" declares a series of the subsequent name):
series GDP_P = GDPn / GDP
series CONS_P = CONSn / CONS
series INV_P = INVn / INV
series GOV_P = GOVn / GOV
series EX_P = EXn / EX
series IM_P = IMn / IM
到目前为止,我已经尝试使用 R for 循环(我读过这不是 R 中的首选方法),方法是创建系列名称的向量并使用 "assign(paste" 进行计算。下面是一个示例,但它不起作用。根据我对 "for" 命令的了解,"i" 的声明系列只能是值向量或名称向量,没有进一步的上下文:
cats<-c("GDP","CONS","GOV","INV","EX","IM")
for (i in cats){
assign(paste(i, "_P",sep=""), paste(i, "n",sep="")/i)
}
我也对 "apply" 函数和派生函数进行了大量阅读,但我看不出它在上述情况下是如何工作的。关于如何在 R 中执行此操作的任何建议都会有所帮助。
你的函数应该像这样工作:
cats<-c("GDP","CONS","GOV","INV","EX","IM")
for (i in cats){
assign(paste(i, "_P",sep=""), get(paste(i, "n",sep=""))/get(i))
}
get
将使用您提供的字符串并找到该名称的向量。
还有一种非 for 循环的方法,使用其中一个答案的想法 here:
txt<-paste0(cats, "_P <- ", cats, "n/", cats)
eval(parse(text=txt))
txt
将包含您必须键入以手动创建所有向量的所有行的列表,然后 eval(parse(text=txt))
获取这些命令中的每一个并逐条执行它们.
您当然可以跳过将文本分配给 txt
-- 我只是想让它更清楚这里发生了什么:
eval(parse(text=paste0(cats, "_P <- ", cats, "n/", cats)))
考虑使用列表,尤其是对于许多相似的元素。这样做,您可以更好地管理您的全球环境并更紧凑、更高效地处理数据。对您来说,这意味着维护 3 个向量列表而不是 18 个单独的命名向量(2 个原始集和新的第 3 个集)。使用 assign
动态创建变量通常表示有机会使用命名列表。
具体来说,在 GDPn_list 和 GDP_list 中收集你的物品,然后使用 Map
(mapply
的非简化包装器)在调用除法函数 /
的两个等长列表之间逐元素迭代。然后用 setNames()
命名列表。下面使用随机数据进行演示,但对于您来说,OP 可以使用注释掉的行来构建列表。
原始数据
cats <- c("GDP","CONS","GOV","INV","EX","IM")
set.seed(9272018)
GDPn_list <- setNames(replicate(6, runif(50)*120, simplify=FALSE), paste0(cats, "n"))
# GDPn_list <- list(GDPn, CONSn, GOVn, INVn, EXn, IMn)
str(GDPn_list)
# List of 6
# $ GDPn : num [1:50] 52.4 31.9 10.6 118.4 66 ...
# $ CONSn: num [1:50] 18.27 22.3 95.13 87.44 9.79 ...
# $ GOVn : num [1:50] 48.83 69.73 113.61 35.53 1.21 ...
# $ INVn : num [1:50] 51.9 96.9 28.2 67.2 19 ...
# $ EXn : num [1:50] 28.3 94.3 42.3 65.5 83.6 ...
# $ IMn : num [1:50] 109.3 26.6 60.2 78.2 55.5 ...
GDP_list <- setNames(replicate(6, runif(50)*100, simplify=FALSE), cats)
# GDPn_list <- list(GDP, CONS, GOV, INV, EX, IM)
str(GDP_list)
# List of 6
# $ GDP : num [1:50] 51.1 65.9 41.5 24.5 87.3 ...
# $ CONS: num [1:50] 47.66 77.32 46.97 48.61 2.98 ...
# $ GOV : num [1:50] 32.6 70.3 21.5 73.4 97.8 ...
# $ INV : num [1:50] 80.7 16.8 57.4 80.7 12.1 ...
# $ EX : num [1:50] 38.1 78.1 40.6 62.8 61.9 ...
# $ IM : num [1:50] 39.8 84.8 11.4 39.7 14.7 ...
新数据
GDPp_list <- setNames(Map(`/`, GDPn_list, GDP_list), paste0(cats, "p"))
str(GDPp_list)
# List of 6
# $ GDPp : num [1:50] 1.025 0.484 0.256 4.835 0.756 ...
# $ CONSp: num [1:50] 0.383 0.288 2.025 1.799 3.286 ...
# $ GOVp : num [1:50] 1.4969 0.9921 5.2891 0.4844 0.0124 ...
# $ INVp : num [1:50] 0.644 5.775 0.491 0.832 1.578 ...
# $ EXp : num [1:50] 0.744 1.207 1.043 1.043 1.352 ...
# $ IMp : num [1:50] 2.747 0.314 5.293 1.971 3.783 ...
而且您仍然可以通过名称或索引号引用您的基础数字向量,而不会丢失任何功能或数据:
GDPp_list$GDPp
GDPp_list$CONSp
GDPp_list$GOVp
...
GDPp_list[[1]]
GDPp_list[[2]]
GDPp_list[[3]]
...
如果是等长向量,则根据您的列表构建一个矩阵!这次使用 mapply
:
GDPp_matrix <- mapply(`/`, GDPn_list, GDP_list)
colnames(GDPp_matrix) <- paste0(cats, "p")
head(GDPp_matrix)
# GDPp CONSp GOVp INVp EXp IMp
# [1,] 1.0252871 0.3832836 1.49687150 0.6436575 0.7441159 2.746551
# [2,] 0.4835700 0.2884577 0.99208666 5.7753575 1.2067694 0.314102
# [3,] 0.2562130 2.0251752 5.28913247 0.4910816 1.0429316 5.292843
# [4,] 4.8345697 1.7987625 0.48436284 0.8322211 1.0431301 1.970523
# [5,] 0.7563794 3.2859395 0.01236608 1.5781949 1.3518592 3.783420
# [6,] 0.1515318 10.9332338 1.10608066 13.7953500 0.7211371 1.918249