Как применить функцию к массиву массивов с плавающей точкой? - PullRequest
2 голосов
/ 24 февраля 2010

Предположим, у меня есть n массивов, где n - переменная (некоторое число больше 2, обычно меньше 10).

Каждый массив имеет k элементов.

У меня также есть массив длины n, который содержит набор весов, которые определяют, как я хотел бы линейно объединить все массивы.

Я пытаюсь создать высокопроизводительную функцию более высокого порядка для объединения этих массивов в F #.

Как я могу это сделать, чтобы я получил функцию, которая принимает массив массивов (arrs - это образец), массив весов (weights), а затем вычисляет взвешенную сумму на основе весов?

let weights = [|.6;;.3;.1|]

let arrs = [| [|.0453;.065345;.07566;1.562;356.6|] ; 
              [|.0873;.075565;.07666;1.562222;3.66|] ; 
              [|.06753;.075675;.04566;1.452;3.4556|] |]

спасибо за любые идеи.

Ответы [ 2 ]

6 голосов
/ 24 февраля 2010

Вот одно из решений:

let combine weights arrs =
  Array.map2 (fun w -> Array.map ((*) w)) weights arrs 
  |> Array.reduce (Array.map2 (+))

EDIT

Вот некоторые (очень необходимые) объяснения того, как это работает. Логически мы хотим сделать следующее:

  1. Примените каждый вес к соответствующему ряду.
  2. Сложите строки с поправкой на вес.

Две строки выше делают именно это.

  1. Мы используем функцию Array.map2, чтобы объединить соответствующие веса и строки; способ, которым мы их объединяем, заключается в умножении каждого элемента в строке на вес, что достигается с помощью внутреннего Array.map.
  2. Теперь у нас есть массив взвешенных строк, и нам нужно сложить их вместе. Мы можем делать это по одному шагу за раз, сохраняя промежуточную сумму, добавляя каждый массив по очереди. То, как мы суммируем два массива поточечно, это снова используем Array.map2, используя (+) как функцию для объединения элементов каждого. Мы заключаем это в Array.reduce, чтобы применить эту функцию добавления к каждой строке по очереди, начиная с первой строки.

Надеюсь, это достаточно элегантный подход к проблеме, хотя стиль без точек, по общему признанию, делает его немного сложным для подражания. Тем не менее, обратите внимание, что это не особенно эффективно; выполнение обновлений на месте, а не создание новых массивов с каждым приложением map, map2 и reduce будет более эффективным. К сожалению, стандартная библиотека не содержит хороших аналогов этих операций, которые работают на месте. Однако было бы относительно легко создать такие аналоги, и они могли бы использоваться почти точно так же, как я это делал здесь.

1 голос
/ 24 февраля 2010

Что-то вроде этого сделало это для меня:

let weights = [|0.6;0.3;0.1|]

let arrs = [| [|0.0453;0.065345;0.07566;1.562;356.6|] ; 
              [|0.0873;0.075565;0.07666;1.562222;3.66|] ; 
              [|0.06753;0.075675;0.04566;1.452;3.4556|] |]

let applyWeight x y = x * y

let rotate (arr:'a[][]) = 
    Array.map (fun y -> (Array.map (fun x -> arr.[x].[y])) [|0..arr.Length - 1|]) [|0..arr.[0].Length - 1|]

let weightedarray = Array.map (fun x -> Array.map(applyWeight (fst x)) (snd x)) (Array.zip weights arrs)

let newarrs = Array.map Array.sum (rotate weightedarray)

printfn "%A" newarrs

Кстати ... 0, предшествующее значению с плавающей запятой, необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...