满足特定条件时用 NaN 或 Inf 替换值
Replace values with NaN or Inf when certain conditions are met
我创建了以下三维模型矩阵:
mockup(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
mockup(:,:,2) = ...
[50, NaN, NaN; ...
47, NaN, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
我也定义了percentTickerAvailable = 0.5
.
因此,这些列代表三种不同资产的股票价格。为了进一步处理,我需要按以下方式操作 NaN 值。
- 如果任何给定行中 NaN 的百分比大于
1 - percentTickerAvailable
,请将这些特定行中的所有值替换为 NaN。也就是说,如果没有足够的资产在该特定行中有价格,则完全忽略该行。
- 如果任何给定 ROW 中 NaN 的百分比小于或等于
1 - percentTickerAvailable
,请将相应的 NaN 替换为 -inf
。
为了清楚起见,"percentage of NaNs in any given ROW"计算如下:
任何给定行中的 NaN 数除以列数。
调整后的模型矩阵应如下所示:
mockupAdj(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
mockupAdj(:,:,2) = ...
[NaN, NaN, NaN; ...
47, -inf, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
到目前为止,我做了以下事情:
function vout = ranking(vin, percentTickerAvailable)
percentNonNaN = 1 - sum(isnan(vin), 2) / size(vin, 2);
NaNIdx = percentNonNaN < percentTickerAvailable;
infIdx = percentNonNaN > percentTickerAvailable & ...
percentNonNaN < 1;
[~, ~, numDimVin] = size(vin);
for i = 1 : numDimVin
vin(NaNIdx(:,:,i) == 1, :, i) = NaN;
end
about = vin;
end % EoF
通过调用 mockupAdj = ranking(mockup, 0.5)
,这已经将 mockup(1,:,2)
中的第一行正确地转换为 {'NaN', 'NaN', 'NaN'}
。但是,我正在为第二点而苦苦挣扎。使用 infIdx
我已经成功识别出对应于第二个条件的行。但我不知道如何正确使用该信息以将 mockup(2,2,2)
中的单个 NaN 替换为 -inf
.
非常感谢任何提示。
这是一个可以使用矢量化解决问题的好例子。我提供了两个版本的代码,一个使用现代语法(包括隐式扩展),一个用于旧版本的 MATLAB。
注意几点:
- 在
NaN
替换阶段,我使用 "trick",其中 0/0
被评估为 NaN
。
- 在
Inf
替换阶段,我使用逻辑 masking/indexing 来访问 vin
. 中的正确元素
R2016b 及更新版本:
function vin = ranking (vin, percentTickerAvailable)
% Find percentage of NaNs on each line:
pNaN = mean(isnan(vin), 2, 'double');
% Fills rows with NaNs:
vin = vin + 0 ./ (1 - ( pNaN >= percentTickerAvailable));
% Replace the rest with -Inf
vin(isnan(vin) & pNaN < percentTickerAvailable) = -Inf;
end
R2016b 之前:
function vin = rankingOld (vin, percentTickerAvailable)
% Find percentage of NaNs on each line:
pNaN = mean(isnan(vin), 2, 'double');
% Fills rows with NaNs:
vin = bsxfun(@plus, vin, 0 ./ (1 - ( pNaN >= percentTickerAvailable)));
% Replace the rest with -Inf
vin(bsxfun(@and, isnan(vin), pNaN < percentTickerAvailable)) = -Inf;
end
您还可以使用逻辑索引来完成此任务:
x(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
x(:,:,2) = ...
[50, NaN, NaN; ...
47, NaN, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
% We fix the threshold
tres = 0.5; %fix the threshold.
% We check if a value = NaN or not.
in = isnan(x);
% Which line have more than 50% of NaN ?.
ind = (sum(in,2)./(size(x,2)))>0.5
% We generate an index
[x1,~,x3] = ind2sub(size(ind),ind);
% We set the NaN index to 0 if the line contains less than 50 % of NaN.
in(x1,:,x3) = 0;
% We calculate the new values.
x(in) = -inf;
x(x1,:,x3) = NaN;
1)
The percentage of NaN in any given row should be smaller than 1
...你说的是比例吗?在这种情况下,这是一个无用的检查,因为它总是如此。还是谈论百分比?在这种情况下,您的代码不会执行您描述的操作。我猜是比率。
2) 根据我的猜测,我有一个后续问题:按照你的描述,mockup(2,2,2) 不应该保持 NaN 吗?该行中有 33% (<50%) 的 NaN,因此它不满足您的条件 2.
3) 根据我认为合乎逻辑的答案,我会更改 percentNaN = sum(isnan(vin), 2) / size(vin, 2);
以提高可读性,并相应地更改 NaNIdx = percentNaN > percentTickerAvailable;
。现在只需在循环前面添加一行:
vin(isnan(vin)) = -inf;
为什么?因为这样你用 -inf 替换了所有的 NaN。稍后,符合条件 1 的将再次被循环覆盖为 NaN。您不需要 InfIdx。
4) 请注意,您的函数目前无法 return vout。让它return vin,你会没事的。
我创建了以下三维模型矩阵:
mockup(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
mockup(:,:,2) = ...
[50, NaN, NaN; ...
47, NaN, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
我也定义了percentTickerAvailable = 0.5
.
因此,这些列代表三种不同资产的股票价格。为了进一步处理,我需要按以下方式操作 NaN 值。
- 如果任何给定行中 NaN 的百分比大于
1 - percentTickerAvailable
,请将这些特定行中的所有值替换为 NaN。也就是说,如果没有足够的资产在该特定行中有价格,则完全忽略该行。 - 如果任何给定 ROW 中 NaN 的百分比小于或等于
1 - percentTickerAvailable
,请将相应的 NaN 替换为-inf
。
为了清楚起见,"percentage of NaNs in any given ROW"计算如下: 任何给定行中的 NaN 数除以列数。
调整后的模型矩阵应如下所示:
mockupAdj(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
mockupAdj(:,:,2) = ...
[NaN, NaN, NaN; ...
47, -inf, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
到目前为止,我做了以下事情:
function vout = ranking(vin, percentTickerAvailable)
percentNonNaN = 1 - sum(isnan(vin), 2) / size(vin, 2);
NaNIdx = percentNonNaN < percentTickerAvailable;
infIdx = percentNonNaN > percentTickerAvailable & ...
percentNonNaN < 1;
[~, ~, numDimVin] = size(vin);
for i = 1 : numDimVin
vin(NaNIdx(:,:,i) == 1, :, i) = NaN;
end
about = vin;
end % EoF
通过调用 mockupAdj = ranking(mockup, 0.5)
,这已经将 mockup(1,:,2)
中的第一行正确地转换为 {'NaN', 'NaN', 'NaN'}
。但是,我正在为第二点而苦苦挣扎。使用 infIdx
我已经成功识别出对应于第二个条件的行。但我不知道如何正确使用该信息以将 mockup(2,2,2)
中的单个 NaN 替换为 -inf
.
非常感谢任何提示。
这是一个可以使用矢量化解决问题的好例子。我提供了两个版本的代码,一个使用现代语法(包括隐式扩展),一个用于旧版本的 MATLAB。
注意几点:
- 在
NaN
替换阶段,我使用 "trick",其中0/0
被评估为NaN
。 - 在
Inf
替换阶段,我使用逻辑 masking/indexing 来访问vin
. 中的正确元素
R2016b 及更新版本:
function vin = ranking (vin, percentTickerAvailable)
% Find percentage of NaNs on each line:
pNaN = mean(isnan(vin), 2, 'double');
% Fills rows with NaNs:
vin = vin + 0 ./ (1 - ( pNaN >= percentTickerAvailable));
% Replace the rest with -Inf
vin(isnan(vin) & pNaN < percentTickerAvailable) = -Inf;
end
R2016b 之前:
function vin = rankingOld (vin, percentTickerAvailable)
% Find percentage of NaNs on each line:
pNaN = mean(isnan(vin), 2, 'double');
% Fills rows with NaNs:
vin = bsxfun(@plus, vin, 0 ./ (1 - ( pNaN >= percentTickerAvailable)));
% Replace the rest with -Inf
vin(bsxfun(@and, isnan(vin), pNaN < percentTickerAvailable)) = -Inf;
end
您还可以使用逻辑索引来完成此任务:
x(:,:,1) = ...
[100, 100, 100; ...
103, 95, 100; ...
101, 85, 100; ...
96, 90, 102; ...
91, 89, 99; ...
97, 91, 97; ...
105, 83, 100];
x(:,:,2) = ...
[50, NaN, NaN; ...
47, NaN, 40; ...
45, 60, 45; ...
47, 65, 45; ...
51, 70, 45; ...
54, 65, 50; ...
62, 80, 55];
% We fix the threshold
tres = 0.5; %fix the threshold.
% We check if a value = NaN or not.
in = isnan(x);
% Which line have more than 50% of NaN ?.
ind = (sum(in,2)./(size(x,2)))>0.5
% We generate an index
[x1,~,x3] = ind2sub(size(ind),ind);
% We set the NaN index to 0 if the line contains less than 50 % of NaN.
in(x1,:,x3) = 0;
% We calculate the new values.
x(in) = -inf;
x(x1,:,x3) = NaN;
1)
The percentage of NaN in any given row should be smaller than 1
...你说的是比例吗?在这种情况下,这是一个无用的检查,因为它总是如此。还是谈论百分比?在这种情况下,您的代码不会执行您描述的操作。我猜是比率。
2) 根据我的猜测,我有一个后续问题:按照你的描述,mockup(2,2,2) 不应该保持 NaN 吗?该行中有 33% (<50%) 的 NaN,因此它不满足您的条件 2.
3) 根据我认为合乎逻辑的答案,我会更改 percentNaN = sum(isnan(vin), 2) / size(vin, 2);
以提高可读性,并相应地更改 NaNIdx = percentNaN > percentTickerAvailable;
。现在只需在循环前面添加一行:
vin(isnan(vin)) = -inf;
为什么?因为这样你用 -inf 替换了所有的 NaN。稍后,符合条件 1 的将再次被循环覆盖为 NaN。您不需要 InfIdx。
4) 请注意,您的函数目前无法 return vout。让它return vin,你会没事的。