【问题标题】:MATLAB function: improving speed/performance of codeMATLAB函数:提高代码的速度/性能
【发布时间】:2013-12-03 00:42:33
【问题描述】:

我正在尝试编写一个函数(参见下面的代码),该函数将创建一个机场列表,其中有超过 1,000 个航班起飞或到达,然后提供一个向量,其中包含 (x, y) 格式。机场和航班数据分别存放在维度为 1x6267 和 1x136010 的单独结构中,每个机场和航班都有一个唯一的 ID 号,对应于结构中的列。尽管我编写的代码确实成功地识别了所有有 1000 多个到达/离开组合的机场,但该函数需要将近 20 分钟才能执行,并且只提供机场的 ID 号,而不是它们在 airports 结构中的索引。我需要对代码进行哪些更改才能使其运行时间低于 5 分钟,以及如何为机场创建 (x,y) 索引向量?任何帮助将不胜感激!谢谢!

附:我对 MATLAB 比较陌生,所以如果这些问题看起来很愚蠢或显而易见,我提前道歉。

function list = Problem10( flights, aircraft, airlines, airports )
a=zeros(1,(length(airports)));
for id=1:length(airports)
    a(id)= FlightsToFrom(flights, id);
end
a(a==0) = [];
[list]=[sort(a)]
end

function tofrom = FlightsToFrom(flights, ID)
sum=0;
for ii=1:length(flights)
    if (isequal (flights(1,ii).from_id, ID))||(isequal (flights(1,ii).to_id, ID))
        sum=sum+1;
        if sum > 1000
            break;
        end
    end
end
if sum <=1000
    tofrom=0;
else
    tofrom=ID;
end
end

以下是数据库外观/行为的一些示例:

(In Workspace)
airports <1x6267 struct>
aircraft <1x384 struct>
airlines <1x1559 struct>
flights <1x136010 struct>

(Inside of struct)
flights(1,6) <1x1 struct>
**Field**       **Value**
airline_id    60
from_id       967
to_id         6252
aircraft_id   18
distance      32
airtime       19
passengers    0
month         1

flights(1,6).from_id <1x1 double>
967


airport(1,176) <1x1 struct>
**Field**       **Value**
code          'AEX'
name          'Alexandria, LA: Alexandria International'

airport(1,176).name <1x40 char>
'Alexandria, LA: Alexandria International'

(In Command Window)

>> airports (2866)

ans = 

    code: 'LAX'
    name: 'Los Angeles, CA: Los Angeles International'

>> airports (1, 2866)

ans = 

    code: 'LAX'
    name: 'Los Angeles, CA: Los Angeles International'

>> airports (4703)

ans = 

    code: 'SEA'
    name: 'Seattle, WA: Seattle/Tacoma International'

>> airports (1, 4703)

ans = 

    code: 'SEA'
    name: 'Seattle, WA: Seattle/Tacoma International'

>> flights (4736)

ans = 

     airline_id: 31
        from_id: 1635
          to_id: 1062
    aircraft_id: 194
       distance: 118
        airtime: 1792
     passengers: 1657
          month: 1

>> flights (1, 4736)

ans = 

     airline_id: 31
        from_id: 1635
          to_id: 1062
    aircraft_id: 194
       distance: 118
        airtime: 1792
     passengers: 1657
          month: 1

>> flights(1,7369).to_id

ans =

   830

>> flights(1,7369).from_id

ans =

        1047

【问题讨论】:

  • 您的flights 似乎是很好的数字和正方形。如果您想更有效/更轻松地处理它,它应该有助于将此信息存储在矩阵而不是结构中。这可能也适用于其他一些结构。
  • 我同意矩阵会更加简单和高效。不幸的是,这是我正在学习的 MATLAB 课程的课堂练习的一部分,所以我不得不按照教授设置数据库的方式进行。

标签: performance matlab optimization vector indexing


【解决方案1】:

您的整个 FlightsToFrom() 函数可以完全矢量化,从而实现以下(还有一些额外的小改进):

function a = Problem10( flights, aircraft, airlines, airports )
    numAirports = length(airports);
    a(numAirports) = 0;  % preallocate: faster than zeros()
    from_ids = [flights.from_id];
    to_ids   = [flights.to_id];
    for id = 1 : numAirports
        a(id) = id * (sum(from_ids==id | to_ids==id) > 1000);
    end
    a(~a) = [];
    %a = sort(a);  % unnecessary - a is already sorted at this stage, by ascending ID!
end

这可能可以进一步向量化,但我认为这些小改动所带来的加速应该足以让任何进一步的性能调整投资成为学术问题,而不是实际问题。

【讨论】:

  • 这非常有效,并以指数方式缩短了时间......非常感谢!我想我已经完全沉浸在循环中(这是我们最近在课堂上一直在做的事情,所以我只是认为这会最有效),以至于我无法找到这个更直接、更智能的解决方案。您的回复很有帮助!
【解决方案2】:

在您的代码中需要时间的是循环整个航班列表 6267 次,因为您为每个机场调用了 FlightsToFrom 函数...如果您只需循环一次航班即可解决此问题,程序将运行 6267快几倍,也就是几分之一秒。我不确定您所说的“机场的索引 x,y 向量”是什么意思——这个向量应该包含什么?无论如何,您至少可以这样循环:

a=zeros(length(airports),length(airports));
for id = 1:length(flights)
     a[flights(1,id).from_id, flights(1,id).to_id] = a[flights(1,id).from_id, flights(1,id).to_id]  + 1; 
end

最后,a 是一个矩阵,其中包含一个航班从不同机场起飞的次数。例如。 a[5,6] 将是从机场 5 到机场 6 的航班的次数。然后您可以使用 MATLAB 的内置函数对该矩阵进行处理,例如。

[row, col] = find(a>1000); 

将为您提供发生超过 1000 次的航班的往返坐标。

highdepartures = find(sum(a,1)>1000)); 
highdarrivals = find(sum(a,2)>1000)); 

将分别为您提供出发/到达次数最多的机场坐标列表。

【讨论】:

    【解决方案3】:

    为了加快速度,我建议

    function tofrom = FlightsToFrom(flights, ID)
    assert(~exist('sum','var'))
    nflights=sum([flights.fromId]==ID)+sum([flights.toId]==ID);
    if nflights <=1000
        tofrom=0;
    else
        tofrom=ID;
    end
    end
    

    关于第二个问题,机场是什么样子的?目前您正在使用循环索引,这与机场 ID 相同吗?

    如果可能,请提供一些示例数据。例如这样一段代码来生成与您的真实数据匹配的随机输入数据:

    numOfAirports=100
    numOfFlights=10000
    for idx=1:numOfFlights
        flights(idx).fromId=randi(numOfAirports);flights(idx).toId=randi(numOfAirports);
    end
    

    【讨论】:

    • 丹尼尔-非常感谢您的帮助!我尝试了您的第一个建议,不幸的是,它未能成功产生正确的结果。而不是我用原始函数得到的机场号码向量,这次产生了空矩阵(我想是因为单独的 from_id 和 to_ids 位于航班结构的单独矩阵中)。循环索引确实与机场 ID 相同。我将重新编辑我的问题以不包含一些示例数据,因此如果您在此之后有任何建议,请告诉我。再次感谢您的帮助!
    • 我更新了我的答案,假设函数 sum 与变量名 sum 存在一些问题。如果断言失败,则有一些全局变量 sum 导致了问题。
    • 我刚刚试用了您的建议,效果很好!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-16
    • 2022-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多