Интерполация и заместване на нули

Имам 3 x n (n е произволно число) матрица в MATLAB. Пример за n=13:

M = [40, 0, 0, 0, 41, 0, 0, 0, 0, 0, 41.6, 0, 20;
     20, 0, 0, 0, 23, 0, 0, 0, 0, 0, 23, 0, 189;
     102, 0, 0, 0, 192, 0, 0, 0, 0, 0, 96, 0, 21];

Броят на нулите между две ненулеви числа във всеки ред е произволен, но това число винаги е едно и също между редовете. Искам да интерполирам всеки ред така:

Minter = [40, 40.25, 40.5, 40.75, 41, 41.1, 41.2, 41.3, 41.4, 41.5, 41.6, 30.8, 20;
          20, 20.75, 21.5, 22.25, 23, 23,   23,   23,   23,   23,   23,   106, 189;
          102, 124.5, 147, 169.5, 192, 176, 160,  144,  128,  112,  96,   58.5, 21];

Така че искам да заменя нулите с числа, получени с метода на линейна интерполация.

Написах собствена функция, за да направя това. Използвам функцията MATLAB find за търсене на индекси на числа, които са >0, и след това в зависимост от разликата между два индекса (от функцията find) и в зависимост от първото дясно и ляво ненулево число (от оригиналната матрица ), изчислявам числа между тези две ненулеви числа и замествам нули с тези числа в оригиналната матрица. Работя върху всеки ред поотделно.

Този метод работи добре, но не е много бърз. Има ли по-бърз начин в MATLAB? Опитах функцията interp1, но без особен успех.


person dejh    schedule 07.06.2015    source източник
comment
Помогна ли ви това, което написах? Проработи ли?   -  person rayryeng    schedule 09.06.2015
comment
ЕХО! ехо!..... д....ч....о.   -  person rayryeng    schedule 17.06.2015
comment
Много се извинявам за късния отговор! Да, работи отлично! Много благодаря!!!   -  person dejh    schedule 24.06.2015
comment
Няма проблем. Приетата практика тук би била да се приеме отговорът ми. Можете да направите това, като отидете на моя отговор, горе и вляво, под стрелките нагоре и надолу... щракнете върху иконата с отметка. Късмет!   -  person rayryeng    schedule 11.07.2015


Отговори (1)


Да, все още можете да използвате interp1, но трябва да бъдете умен за това. Като вземем предвид факта, че интерполирате всеки ред от вашата матрица отделно, можем да използваме find и можем да оперираме с транспонирането на матрицата, за да намерим онези местоположения на основните колони, които са различни от нула. Това е важно, защото искаме да интерполираме стойностите на матрицата на ред и find работи в реда на главните колони. Ако искате да работите на ред, ще трябва да транспонирате матрицата, за да получите желания ефект.

След като сте готови, можете да използвате тези индекси, както и онези стойности в транспонирането на матрицата, които не са празни като ключови точки, след което да използвате точки за справка, които варират от 1 до толкова елементи, колкото имаме в M до попълнете онези стойности в M, които са нула. Това обаче ще ни даде само 1D масив, така че ще трябва да reshape матрицата и транспониране обратно, когато сме готови. Транспонирането отново е важно, защото reshape преоформя вектора по главна колона, така че тази последна стъпка гарантира, че получаваме всичко в главна колона.

Направете нещо подобно:

%// Your matrix
M=[40, 0, 0, 0, 41, 0, 0, 0, 0, 0, 41.6, 0, 20;
20, 0, 0, 0, 23, 0, 0, 0, 0, 0, 23, 0, 189;
102, 0, 0, 0, 192, 0, 0, 0, 0, 0, 96, 0, 21];

%// New code
Mt = M.'; %// Transpose
ind = find(Mt); %// Find column-major indices
Minter = interp1(ind, Mt(ind), 1:numel(M)); %// Interpolate per row
Minter = reshape(Minter, size(M,2), size(M,1)).'; %// Reshape and transpose back

Получаваме:

Minter =

  Columns 1 through 8

   40.0000   40.2500   40.5000   40.7500   41.0000   41.1000   41.2000   41.3000
   20.0000   20.7500   21.5000   22.2500   23.0000   23.0000   23.0000   23.0000
  102.0000  124.5000  147.0000  169.5000  192.0000  176.0000  160.0000  144.0000

  Columns 9 through 13

   41.4000   41.5000   41.6000   30.8000   20.0000
   23.0000   23.0000   23.0000  106.0000  189.0000
  128.0000  112.0000   96.0000   58.5000   21.0000

Това е в съответствие с желания резултат.

person rayryeng    schedule 07.06.2015