Есть пара вещей, которые нужно сделать, чтобы достичь желаемого. Во-первых, учитывая количество делений, мы должны разделить 2-мерное пространство. Во-вторых, используя счетчик делений, нам нужен гибкий метод группировки фиксаций в соответствующие места. Наконец, мы генерируем любую статистику, которая вам нужна.
Что касается подсчета делений, встроенная функция FactorInteger
почти делает то, что вам нужно. Например,
(* The second parameter is the upper limit for the number of factors returned *)
FactorInteger[35,2] == {{5,1}, {7,1}}
FactorInteger[64,2] == {{2,6}}
К сожалению, вы можете указать только верхний предел для числа возвращаемых факторов, поэтому мы должны немного изменить вывод
Clear[divisionCount]
divisionCount[c_Integer?(Positive[#] && (# == 2 || ! PrimeQ[#]) &)] :=
With[{res = FactorInteger[c, 2]},
Power @@@ If[
Length[res] == 2,
res // Reverse,
With[
{q = Quotient[res[[1, 2]], 2], r = Mod[res[[1, 2]], 2],
b = res[[1, 1]]},
{{b, q + r}, {b, q}}
]
]
]
Это делает две вещи, заменяет {{b,m}}
на {{b, m / 2 + m mod 2}, {b, m / 2}}
, где /
представляет целочисленное деление (т.е. есть остатки) и преобразует {{b, m} ..}
в {b^m ..}
через Power @@@
. Это дает
divisionCount[32] == {8, 4}
divisionCount[64] == {8, 8}.
Оказывается, мы можем получить количество фиксаций в этот момент с минимальной дополнительной работой через BinCounts
следующим образом
BinCounts[fix[[All,;;2]], (* stripping duration from tuples *)
{xmin, xmax, (xmax - xmin)/#1,
{ymin, ymax, (ymax - ymin)/#2]& @@ divisionCount[ divs ]
, где вам нужно указать диапазоны для x
и y
и количество делений. Однако это не так гибко, как могло бы быть. Вместо этого мы будем использовать SelectEquivalents
.
Ключом к эффективному использованию SelectEquivalents
является создание хорошей функции категоризации. Для этого нам нужно самим определить деления следующим образом
Clear[makeDivisions]
makeDivisions[
{xmin_, xmax_, xdivs_Integer?Positive}, {ymin_, ymax_, ydivs_Integer?Positive}] :=
Partition[#,2,1]& /@ {
(xmax - xmin)*Range[0, xdivs]/xdivs + xmin,
(ymax - ymin)*Range[0, ydivs]/ydivs + ymin
}
makeDivisions[
{xmin_, xmax_}, {ymin_, ymax_},
divs_Integer?(Positive[#] && (# == 2 || ! PrimeQ[#]) &)] :=
makeDivisions[{xmin, xmax, #1}, {ymin, ymax, #2}] & @@ divisionCount[divs]
, где
makeDivisions[{0, 1}, {0, 1}, 6] ==
{{{0, 1/3}, {1/3, 2/3}, {2/3, 1}}, {{0, 1/2}, {1/2, 1}}}.
(я бы использовал FindDivisions
, но он не всегда возвращает количество запрошенных вами делений.) makeDivisions
возвращает два списка, где каждый термин в каждом списке является минимальным-максимальным пара, которую мы можем использовать, чтобы определить, попадает ли точка в корзину.
Поскольку мы находимся на квадратной решетке, нам нужно проверить все пары пределов, которые мы только что определили. Я бы использовал следующее
Clear[inBinQ, categorize]
inBinQ[{xmin_,xmax_}, {ymin_, ymax_}, {x_,y_}]:=
(xmin <= x < xmax) && (ymin <= y < ymax)
categorize[{xmin_, xmax_}, {ymin_, ymax_}, divs_][val : {x_, y_, t_}] :=
With[{bins = makeDivisions[{xmin, xmax}, {ymin, ymax}, divs]},
Outer[inBinQ[#1, #2, {x, y}] &, bins[[1]], bins[[2]], 1]] //Transpose
, который возвращает
categorize[{0,1},{0,1},6][{0.1, 0.2, 5}] ==
{{True, False, False}, {False, False, False}}.
Обратите внимание, координата y обращена по сравнению с графиком, низкие значения находятся в начале массива. Чтобы «исправить» это, Reverse
bins[[2]]
в categorize
. Кроме того, вы захотите удалить Transpose
до предоставления результатов в MatrixPlot
, так как он ожидает результаты в нетранспонированной форме.
Использование
SelectEquivalents[
fix,
(categorize[{xmin, xmax}, {ymin, ymax}, 6][#] /. {True -> 1, False -> 0} &),
#[[3]] &, (* strip off all but the timing data *)
{#1, #2} &],
получаем
{{
{{0, 0, 0}, {0, 1, 0}}, {774., 518., 161., 121., 273., 177., 217., 406.}
},
{
{{0, 0, 0}, {0, 0, 1}}, {200., 236.}
},
{
{{0, 0, 1}, {0, 0, 0}}, {176., 154.}
},
{
{{0, 1, 0}, {0, 0, 0}}, {124., 119., 366.}
}}}
где первый член в каждом подсписке является матричным представлением ячейки, а второй член - это список точек, попадающих в эту ячейку. Чтобы определить, сколько в каждой корзине,
Plus @@ (Times @@@ ({#1, Length[#2]} & @@@ %)) ==
{{0, 3, 2}, {0, 8, 2}}
Или время
Plus @@ (Times @@@ ({#1, Total[#2]} & @@@ %)) ==
{{0, 609., 330.}, {0, 2647., 436.}}
Редактировать : Как вы можете видеть, чтобы получить любую статистику, необходимую вам для фиксаций, вам нужно просто заменить либо Length
или Total
. Например, вам может потребоваться среднее (Mean
) потраченное время, а не только общее.