【问题标题】:sumproduct on condition that text strings matchsumproduct 在文本字符串匹配的条件下
【发布时间】:2012-08-01 12:53:49
【问题描述】:

感谢您对我的帖子表现出兴趣:)

让我快速描述一下我正在使用的数据:

我将 excel 中的重要数据放入我的 matlab 脚本中,因此我最终得到了 3 个向量。它们是:

  • “FIT_txt”(约 25 万行,每个单元格中包含混合的字母和数字。重复条目)
  • “FIT_num”(与仅包含数字的“FIT_txt”的行数相同)
  • “扇区”(约 5k 行,每个单元格中包含混合字母和数字。唯一条目)

现在,我想要实现的目标:

  1. 创建一个向量,计算“扇区”中每一行在“FIT_txt”中出现的次数。例如:假设“sector”中的第一个条目是“AB10”,那么我想创建一个向量来计算“AB10”在“FIT_txt”中出现的次数;这应该保存在新向量的第一行。新向量的第二行计算“FIT_txt”中“扇区”(比如“AB11”)中第2行的出现次数等。

  2. 创建一个向量,将“FIT_num”中出现在与“FIT_txt”中对应于“扇区”条目的条目在同一行中的所有数字相加,并相应地对其进行排序。例如:“扇区”的第 1 行中的“AB10”在“FIT_txt”中出现 3 次 - 它出现在第 2、500 和 2000 行。我想将“FIT_num”中的第 2、500 和 2000 行相加并将它们放入新向量的第一行。

现在,这是对我的问题的简化;本质上,我正在使用更多数据,并且我正在重复此过程以找到更多数量的新向量/矩阵。关于简化,我已经设法通过这样做来解决问题:

units = zeros(length(sector),1);
installed = zeros(length(sector),1);    

for a = 1:length(sector)
        for z = 1:length(FIT_txt(:,1))

            if strcmp((FIT_txt(z,1)),(sector(a)))==1

                units(a,1) = units(a,1) + 1;
                installed(a,1) = installed(a,1) + FIT_num(z,1);

            end

        end
    end

不幸的是,我担心这是非常低效的,而且计算时间太长。

我已经成功地在我的第一个问题(计算出现次数)上取得了不错的结果:

units = zeros(length(sector),1);

for a = 1:length(sector)
    units(a,1) = sum(strcmp((FIT_txt(:,1)),(sector(a)))
end

效果很好(尽管仍然比我想要的要长一点),但是,我不知道如何解决我的第二个问题(计算“FIT_num”中对应的值)。

如果您能帮助我找到尽可能有效地解决我的问题的解决方案,我将不胜感激。

非常感谢您。

约翰

【问题讨论】:

  • sector 中的一行可以在FIT_txt 的每行中出现两次吗?总和应该怎么比去?按出现次数加权还是仅添加或不添加?另外,FIT_txt, 250x1 元胞数组是什么数据类型?
  • 感谢冈瑟的回复。 “扇区”中的大多数行在“FIT_txt”中出现多次。我想a)计算“扇区”中的每个条目出现在“FIT_txt”中的次数。 b) 对“FIT_num”中与“FIT_txt”在同一行中对应于“sector”中相同条目的所有值求和。那有意义吗?抱歉,我觉得有点难以表达。
  • 但是一个扇区行可以在一个 FIT_txt 行中出现多次吗?例如,sector(1) = 'AB10',它在FIT_txt 的第一行出现了两次。 FIT_num 中的对应值现在应该计算两次吗?
  • 啊。每行只能出现一次。即,您不会得到类似 FIT_txt(1)='AB10AB10' 的内容,它只会包含“AB10”,因此与扇区 (1) 完全相同。
  • 澄清一下:“FIT_txt”和“FIT_num”的格式为 (x,1),其中 x 大约为 250000。“sector”具有相同的格式,但行数要少得多 (~5k)。

标签: string matlab strcmp


【解决方案1】:

让我们一步一步解决这个问题:我假设 FIT_txt 是一个 Nx1 元胞数组,sector 是一个Mx1 元胞数组。

首先找到FIT_txt中sector(ii)出现的行,以及出现的次数:

ii=1;
sector_occurrence = strfind(FIT_txt,sector(ii));

这为您提供了 FIT_txt 每一行的N 单元格,每个单元格中的每一行都有找到sector(ii) 的实际位置。您只需要每行的计数,因此请使用 numel 来获得:

cellfun(@numel,sector_occurrence );

您可以使用循环或 arrayfunsector 的每个元素执行此操作:

sector_occurrence = cell2mat(arrayfun(@(ii) cellfun(@numel,strfind(FIT_txt,sector{ii})),1:numel(sector),'uni',false'));

现在你有一个 NxM 矩阵。第 i 行第 j 列的元素告诉sector(j)FIT_txt(i) 中出现了多少次。

*正在阅读您的 cmets... 啊,但是如果找到一个扇区,FIT_txt 正好等于该扇区,这允许您使用 strcmp 和 arrayfun 简化上述所有操作:

sector_occurrence = cell2mat(arrayfun(@(sectorii) strcmp(FIT_txt,sectorii), sector', 'uni',false))



现在总结:

它只是出现向量与FIT_num 的向量积,您可以通过将sector_occurrence 矩阵与FIT_num 相乘来一次调用它们:

sumresult = sector_occurrence'*FIT_num;

注意转置运算符',因为sector_occurrence 被定义为NxM

示例

>> sector=[{'AB10'} ; {'b'}];
>> FIT_txt=[{'AB10'} ; {'a'} ; {'b'} ; {'ZX5b'} ; {'AB10'} ; {'b'}];
>> FIT_num = (1:6)';

>> sector_occurrence = strfind(FIT_txt,sector(ii))

sector_occurrence =

     1     0
     0     0
     0     1
     0     0
     1     0
     0     1

>> sumresult = sector_occurrence'*FIT_num

sumresult =

     6
     9

当然,它必须是完全匹配(你说的是)b 不会等于 B 也不等于 bb,只有 b

大数据集备注

sector_occurrence 是一个logical 数组,所以它不需要那么多内存。但是当使用FIT_num 执行乘法时,它会转换为float,这需要8 倍的空间。最终结果是一个小的(内存中的)向量,但中间过程可以融化你的电脑。您可以通过在循环中进行乘法来避免这种情况:

sumresult=NaN(numel(sector),1); %preallocation is a good thing
for ii=1:numel(sector)
    sumresult(ii)=sector_occurrence(:,ii)'*FIT_num;
end

【讨论】:

  • 谢谢。当我运行脚本的第一部分时,出现以下错误:“??? Error using ==> cell.strfind at 35 如果任何输入参数是元胞数组,则第一个必须是字符串元胞数组,并且second 必须是一个字符数组。”。
  • 可以重试吗?我忘了添加一些东西(见编辑)。顺便说一句,你实际上只需要最后两行代码
  • 已经尝试过“sector_occurrence = cell2mat(arrayfun(@(sectorii) strcmp(c,x),sector','uni',false))” - 它对我来说不太有效。老实说,我还没有很好地理解代码。它无法识别 c 和 x - 我已将它们替换为 FIT_txt 和扇区(正确吗?),但它产生以下错误:“错误使用 ==> strcmp 输入的大小必须相同,或者任何一个都可以是标量.".
  • 哎呀,今天的第二个错误:现在已修复和测试。不明白的就去查文档里面的函数,一点一点的去测试,虽然不标准,但也没有那么难。
  • 非常感谢您的时间和精力。它现在不返回错误,但由于某种原因,矩阵现在只包含“0”值。此外,我需要使用大量数据创建多个这样的矩阵,并且内存不足。我想我需要找到一个不需要这么大矩阵的解决方案;与我在原始帖子(第二个示例)中发布的内容类似的内容会更好,因为它需要更少的 CPU 和内存;该示例的问题是我无法使 Fit_num 总和起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 2015-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多