Matlab——批量操作变量(把字符变为变量名)
问题
如果有个Data.mat文件,其中含有一系列变量data_20220929,data_20220930,data_20221001……,你需要批量导入,对每个做相同的操作(本文只是显示一下)。思路是把不同的变量名设置为相同的变量名,然后使用相同的代码来个for循环就行了。有三种方法可以实现。
涉及的问题有: 对变量批量操作 , 字符串变为变量名使用eval , 结构体索引 , 并行计算parfor与eval冲突 。
先构造一下数据:
data_20220929 = 1;
data_20220930 = 2;
data_20221001 = 3;
data_20221002 = 4;
mkdir('myfile\')
save('myfile\Data.mat','data*');
方法一:使用eval,
加载mat文件中的变量,使用eval批量执行表达式,把变量改为同一个名字。代码示例如下:
读取执行:
load myfile\Data.mat; %加载变量
dataname = who('data*'); % 读取工作区变量名,读出来的是cell
for i = 1:length(dataname)
eval(['datai = ' dataname{i} ';']);
disp(datai);
end
优点:理解简单,代码简单;
缺点:1. eval执行效率相对较低,低多少不知道,matlab帮助手册上说的。2. eval不能使用在并行计算中,如果你把for改为parfor,那么eval就执行不了。你可以想象,如果你的数据非常多,并行计算的话,效率可以成倍提高,但是你现在用不了,就很烦。
方法二:并行+函数包装eval
对方法一中,eval不能在parfor中运行的问题进行解决,可以使用函数把eval部分封装出来执行,网上大多使用这个方法解决冲突,但此速度反而会比第一个慢。
load myfile\Data.mat; %加载变量
dataname = who('data*'); % 读取工作区变量名,读出来的是cell
parfor i = 1:length(dataname)
f(dataname{i});
function f(dataname)
load('myfile\Data.mat', dataname);
eval(['datai=' dataname ';']);
disp(datai);
end
优点:可以并行计算。
缺点:1. 仍然有eval。2. 使用函数调用速度慢。
方法三:并行+结构体索引
eval是读取过后改名字,如果能在读取时就顺便把名字改了就好了,避免使用eval的同时还可以直接并行。不可以直接这么干,但可以曲线救国。load具有返回值,为结构体,结构体名字可以随便定义。这时你可能会发现,结构体中存储的还是以原来名字命名的变量,以为回到了原点,又要用eval,其实不然,结构体的访问可以不用eval,它的访问特点中就支持序号索引。:
data = load('myfile\Data.mat'); % 读取结果为结构体
dataname = fieldnames(data); % 获取结构体名称
parfor i = 1:length(dataname)
datai = data.(dataname{i}); % 重命名变量。其实这里和下面合并也行,不过代码就不好看了。
disp(datai);
end
优点:避免使用eval,可以并行;
运行时间测试
首先生成一万个变量( 参考CSDN ),然后分别修改以上三个操作的代码并运行(去除了disp显示):
VarNum = 10000; %生成变量的数目,可任意修改
vars = [];
for i = 1:VarNum
vars{1,i} = ['x',num2str(i-1)];