I am working with very large binary arrays on the order of {100,100000}. It may look something like this.
data = N[Table[RandomInteger[], {i, 100}, {j, 100000}]];
What I am then trying to do with this data is replace high densities of 1.'s with 0.s in each row. For instance, if I look at successive chunks of 20 in each row and find that it has 15 1.s I want to then make them all 0.s. Now, I know that I can index through each row summing up every 20 indices and determine if the sum is 15 or more. If so, then I can make them all 0. However, indexing through large arrays in this fashion can be very time consuming. Here is a small scale example of what I want to do. In this smaller scale of data I am zeroing out densities of 3 or more for every 5 indices and leaving everything else the same.
data = N[Table[RandomInteger[], {i, 2}, {j, 20}]]
{{1., 0., 0., 1., 0., 1., 0., 1., 0., 1., 1., 0., 0., 0., 1., 1., 0.,
0., 0., 1.}, {0., 1., 0., 0., 1., 1., 0., 1., 0., 1., 0., 0., 1.,
0., 1., 0., 0., 0., 1., 1.}}
Do[
z = Total[data[[i]][[j ;; j + 4]]];
If[z >= 3,
data = ReplacePart[data, Table[{i, j + k}, {k, 0, 4}] -> N[0]]], {i,
1, Dimensions[data][[1]]}, {j, 1, Dimensions[data][[2]], 5}]
data
{{1., 0., 0., 1., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 1., 1., 0.,
0., 0., 1.}, {0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 1.,
0., 1., 0., 0., 0., 1., 1.}}
I need to find a way to do this as fast as possible with really big arrays. This way takes a long time for a {20,100000} array looking at every 20 indices zeroing out densities of 15 or more. As you can see...
data = N[Table[RandomInteger[], {i, 20}, {j, 100000}]];
Do[
z = Total[data[[i]][[j ;; j + 19]]];
If[z >= 15, data = ReplacePart[data, Table[{i, j + k}, {k, 0, 19}] -> N[0]]], {i, 1,
Dimensions[data][[1]]}, {j, 1, Dimensions[data][[2]], 20}] // AbsoluteTiming
{18.767073, Null}
A {100,100000} array would obviously take longer. I've tried some pattern ideas, see the following Replacing Patterns In a List of Varying Length, but that didn't quite do it since the pattern of 1.s had to be exact before replacing.
Partition
would do most of the work for you. $\endgroup$ListCorrelate
/L:istConvolve
? Looking at 1D (i.e. a row) now, take a vector (row), and compute the correlation/convolution with{1, 1, ..., 1}
. The positions where the correlation is high give you high densities of 1s. Then take this correlation vector, applyUnitStep
to it with a threshold, so you get 1 at high densities and 0 elsewhere. FInally subtract it form the original vector to eliminate high densities of 1s and then apply UnitStep again to get rid of potential -1s. $\endgroup$kernel=ConstantArray[1., 20]; result = UnitStep[# - 0.5 - N@Unitize@ListCorrelate[kernel, UnitStep[ListCorrelate[kernel, #, {1, 1}, 0.] - 15.], {1, 1}, 0.]] & /@ data;
$\endgroup$MinFilter
/MaxFilter
,etc.). You can probably get sneaky, convert array to image, and use image processing for ludicrous speed, then convert back to numeric... $\endgroup$