我有两个具有不同列数的数据集:
ds1:
A B C
1 2 3
ds2:
A C D
2 3 4
现在我想合并这两个数据集:
结果:
A B C D
1 2 3 0
2 3 0 4
如您所见,如果两个数据集中都不存在变量名称,我只想添加 0、NaN 或空白。我尝试使用cat
and join
,但我不知道该怎么做。有什么提示吗?
我有两个具有不同列数的数据集:
ds1:
A B C
1 2 3
ds2:
A C D
2 3 4
现在我想合并这两个数据集:
结果:
A B C D
1 2 3 0
2 3 0 4
如您所见,如果两个数据集中都不存在变量名称,我只想添加 0、NaN 或空白。我尝试使用cat
and join
,但我不知道该怎么做。有什么提示吗?
我会去做这样的事情。它用零填充最终矩阵。
%examples (ABCD are replaced by indexes 1234)
A = [1 2 3; 11 12 13];
B = [1 3 5 8; 111 112 113 114];
%first mix the first rows of A and B
header = union(A(1,:), B(1,:))
%find the corresponding indexes in A and B
[Lia,LocbA] = ismember(A(1,:),header);
[Lia,LocbB] = ismember(B(1,:),header);
%concatenate the second rows of A and B
C = header
C(2,LocbA) = A(2,:);
C(3,LocbB) = B(2,:);
结果:
一个=
1 2 3
11 12 13
乙 =
1 3 5 8
111 112 113 114
C =
1 2 3 5 8
11 12 13 0 0
111 0 112 113 114
编辑:最初提供的代码也适用于单元格(参见下面的示例)。在这种情况下,它会用空单元格填充最终的单元格数组。与@Floris 解决方案相反,要合并的数据集由列标题(第一行)和数据(第二行)组成。我猜您拥有的数据格式将适合这两种解决方案之一。
%input modification (now with cells)
A = {'A' 'B' 'C'; 11 12 13};
B = {'A' 'C' 'E' 'H'; 111 112 113 114};
结果:
C =
'A' 'B' 'C' 'E' 'H'
[ 11] [12] [ 13] [] []
[111] [] [112] [113] [114]
这是一种丑陋的方法 - 然后是一种更清洁的方法(稍后添加)。问题是,一旦您使用元胞数组(因为数据类型是混合的 - 列的字母,然后是数字),生活就会变得艰难。您可以通过创建一个列名和数据是两个独立数组的结构来做得更好(见下文)......但现在这里是“一个解决方案”。通过在两个数据集中使用不同数量的行以及不同数量的列,我让生活变得更加有趣——只是为了确保不会破坏某些东西。
ds1 = {'a','bb','c';1,2,3};
ds2 = {'aa','c','d', 'e';2,3,4,5; 5,6,7,8};
cols = unique({ds1{1,:} ds2{1,:}});
ds3 = cols;
n1 = size(ds1,1) - 1;
%%
for ii = 1:size(ds1,2)
ci = find(cellfun(@(x) isequal(x, ds1{1,ii}), cols));
if numel(ci) > 0
for jj = 1:n1
ds3{1+jj,ci} = ds1{1+jj, ii};
end
end
end
n2 = size(ds2, 1) - 1;
for ii = 1:size(ds2,2)
ci = find(cellfun(@(x) isequal(x, ds2{1,ii}), cols));
if numel(ci) > 0
for jj = 1:n2
ds3{1+n1+jj,ci} = ds2{1+jj, ii};
end
end
end
生成的合并数组:
'a' 'aa' 'bb' 'c' 'd' 'e'
[1] [] [ 2] [3] [] []
[] [ 2] [] [3] [4] [5]
[] [ 5] [] [6] [7] [8]
我敢肯定,这不是最佳选择-但它可以满足您的要求...我讨厌循环执行此操作,但看不到解决方法。我希望一位“真正的 Matlab 专家”在看到这一点时会呕吐,并被激励给你一个聪明的单行答案。
编辑我对此进行了更多思考,并提出了一个更有效的算法:
% assuming column headers and data are in two separate arrays
ds1headers = {'a','bb','c'};
ds1data = [1 2 3; 2 3 4];
ds2headers = {'aa','c','d', 'e'};
ds2data = [2 3 4 5; 3 4 5 6; 4 5 6 7];
% as before, find unique column headers:
cols = unique({ds1headers{:} ds2headers{:}});
% convert to column numbers:
ds1conv = cellfun(@(x)find(ismember(cols, x)), ds1headers);
ds2conv = cellfun(@(x)find(ismember(cols, x)), ds2headers);
% now conversion is easy:
n1 = size(ds1data,1);
n2 = size(ds2data,1);
ds3data = zeros(n1+n2, numel(cols));
ds3data(1:n1, ds1conv) = ds1data;
ds3data(n1+(1:n2), ds2conv) = ds2data;
disp(cols)
disp(ds3data)
结果是
'a' 'aa' 'bb' 'c' 'd' 'e'
1 0 2 3 0 0
2 0 3 4 0 0
0 2 0 3 4 5
0 3 0 4 5 6
0 4 0 5 6 7
看起来它可以解决问题 - 并且没有丑陋的循环......我现在认识到这看起来有点像下面的@Magla 的解决方案(当我发布我的更新时没有看到它,但在我最近的编辑之前它显然就在那里) - 除了我还有一个用于列名的单元格数组,以及一些其他改进。
首先我们创建示例:
% Create test datasets:
A=1;
B=2;
C=3;
save db1
A=2;
clear B;
D=4;
save db2
clear;
现在脚本看起来或多或少像:
% Your script starts here, replace your paths with the correct paths:
path_to_db1 = 'db1';
path_to_db2 = 'db2';
db1 = load(path_to_db1);
db2 = load(path_to_db2);
merge = db1;
for field = fieldnames(db1)'
field = field{1};
if isfield(db2,field)
merge.(field) = [merge.(field);db2.(field)];
else
merge.(field) = [merge.(field);0];
end
end
for field = fieldnames(db2)'
field = field{1};
if ~isfield(db1,field)
merge.(field) = [0;db2.(field)];
end
end
clear db1 db2;
输出:
>> merge.A
ans =
1
2
>> merge.B
ans =
2
0
>> merge.C
ans =
3
3
>> merge.D
ans =
0
4
但是您可能希望它们成为工作区上的自由变量,而不是合并结构上的自由变量,因此您可以添加以下代码:
for field = fieldnames(merge)'
field=field{1};
eval(sprintf('%s = merge.%s;',field,field));
end