Related
I want to select elements with its indexes based on given condition for n dimension array
I have solution for two dimension array like below
ary = [
['A', 'B', 'C'],
['D', 'E', 'F'],
['G', 'H', 'I']
]
new_ary = ary.collect.with_index do |row, index_r|
row.collect.with_index { |col, index_c| [col, index_r, index_c] if index_c == 0 }.compact
end
new_ary.flatten(1)
=> [["A", 0, 0], ["D", 1, 0], ["G", 2, 0]]
I want this solution for n dimension
it would be great if method works like this
ary.select_with_indexes { |val, index_c ,index_c,...| index_c == 0 }
# x,y,... is indexes
# val is value of x,y,... index
# x == 0 is condition for select element, this condition is only for understanding. we will put any condition there
Three dimension array like below
ary = [[
['A1', 'B1', 'C1'],
['D1', 'E1', 'F1'],
['G1', 'H1', 'I1']
],[
['A2', 'B2', 'C2'],
['D2', 'E2', 'F2'],
['G2', 'H2', 'I2']
],[
['A3', 'B3', 'C3'],
['D3', 'E3', 'F3'],
['G3', 'H3', 'I3']
]]
new_ary = ary.collect.with_index do |row, index_r|
row.collect.with_index do |col, index_c|
col.collect.with_index do |val, index_d|
[val, index_r, index_c, index_d] if index_d == 0
end.compact
end
end
new_ary.flatten(1)
=> [[["A1", 0, 0, 0]], [["D1", 0, 1, 0]], [["G1", 0, 2, 0]], [["A2", 1, 0, 0]], [["D2", 1, 1, 0]], [["G2", 1, 2, 0]], [["A3", 2, 0, 0]], [["D3", 2, 1, 0]], [["G3", 2, 2, 0]]]
index_d == 0 this condition is only for understanding
we will put any condition there
Code
In the examples in the question the index of the innermost array is always zero. I have made that an argument, most_inner_index.
def doit(ary, most_inner_index)
first, *rest = nested_indices(ary)
first.product(*rest).map do |indices|
[ary.dig(*indices, most_inner_index), *indices, most_inner_index]
end
end
def nested_indices(ary)
sizes = []
while ary.first.is_a?(Array)
sizes << ary.size.times.to_a
ary = ary.first
end
sizes
end
Examples
ary2 = [
['A', 'B', 'C'],
['D', 'E', 'F'],
['G', 'H', 'I']
]
doit(ary2, 0)
#=> [["A", 0, 0], ["D", 1, 0], ["G", 2, 0]]
doit(ary2, 1)
#=> [["B", 0, 1], ["E", 1, 1], ["H", 2, 1]]
doit(ary2, 2)
#=> [["C", 0, 2], ["F", 1, 2], ["I", 2, 2]]
ary3 = [[
['A1', 'B1', 'C1'],
['D1', 'E1', 'F1'],
['G1', 'H1', 'I1']
],[
['A2', 'B2', 'C2'],
['D2', 'E2', 'F2'],
['G2', 'H2', 'I2']
],[
['A3', 'B3', 'C3'],
['D3', 'E3', 'F3'],
['G3', 'H3', 'I3']
]]
doit(ary3, 0)
#=> [["A1", 0, 0, 0], ["D1", 0, 1, 0], ["G1", 0, 2, 0],
# ["A2", 1, 0, 0], ["D2", 1, 1, 0], ["G2", 1, 2, 0],
# ["A3", 2, 0, 0], ["D3", 2, 1, 0], ["G3", 2, 2, 0]]
doit(ary3, 1)
#=> [["B1", 0, 0, 1], ["E1", 0, 1, 1], ["H1", 0, 2, 1],
# ["B2", 1, 0, 1], ["E2", 1, 1, 1], ["H2", 1, 2, 1],
# ["B3", 2, 0, 1], ["E3", 2, 1, 1], ["H3", 2, 2, 1]]
doit(ary3, 2)
#=> [["C1", 0, 0, 2], ["F1", 0, 1, 2], ["I1", 0, 2, 2],
# ["C2", 1, 0, 2], ["F2", 1, 1, 2], ["I2", 1, 2, 2],
# ["C3", 2, 0, 2], ["F3", 2, 1, 2], ["I3", 2, 2, 2]]
Notice that the return values are not quite in the form desired. That is because I could not figure out from the question how many nested arrays were desired.
ary4 = [
[
[
[['A1', 'B1'], ['C1', 'D1']],
[['E1', 'F1'], ['G1', 'H1']]
],
[
[['I1', 'J1'], ['K1', 'L1']],
[['M1', 'N1'], ['O1', 'P1']]
]
],
[
[
[['A2', 'B2'], ['C2', 'D2']],
[['E2', 'F2'], ['G2', 'H2']]
],
[
[['I2', 'J2'], ['K2', 'L2']],
[['M2', 'N2'], ['O2', 'P2']]
]
],
[
[
[['A3', 'B3'], ['C3', 'D3']],
[['E3', 'F3'], ['G3', 'H3']]
],
[
[['I3', 'J3'], ['K3', 'L3']],
[['M3', 'N3'], ['O3', 'P3']]
]
]
]
doit(ary4, 0)
#=> [["A1", 0, 0, 0, 0, 0], ["C1", 0, 0, 0, 1, 0], ["E1", 0, 0, 1, 0, 0],
# ["G1", 0, 0, 1, 1, 0], ["I1", 0, 1, 0, 0, 0], ["K1", 0, 1, 0, 1, 0],
# ["M1", 0, 1, 1, 0, 0], ["O1", 0, 1, 1, 1, 0], ["A2", 1, 0, 0, 0, 0],
# ["C2", 1, 0, 0, 1, 0], ["E2", 1, 0, 1, 0, 0], ["G2", 1, 0, 1, 1, 0],
# ["I2", 1, 1, 0, 0, 0], ["K2", 1, 1, 0, 1, 0], ["M2", 1, 1, 1, 0, 0],
# ["O2", 1, 1, 1, 1, 0], ["A3", 2, 0, 0, 0, 0], ["C3", 2, 0, 0, 1, 0],
# ["E3", 2, 0, 1, 0, 0], ["G3", 2, 0, 1, 1, 0], ["I3", 2, 1, 0, 0, 0],
# ["K3", 2, 1, 0, 1, 0], ["M3", 2, 1, 1, 0, 0], ["O3", 2, 1, 1, 1, 0]]
doit(ary4, 1)
#=> [["B1", 0, 0, 0, 0, 1], ["D1", 0, 0, 0, 1, 1], ["F1", 0, 0, 1, 0, 1],
# ["H1", 0, 0, 1, 1, 1], ["J1", 0, 1, 0, 0, 1], ["L1", 0, 1, 0, 1, 1],
# ["N1", 0, 1, 1, 0, 1], ["P1", 0, 1, 1, 1, 1], ["B2", 1, 0, 0, 0, 1],
# ["D2", 1, 0, 0, 1, 1], ["F2", 1, 0, 1, 0, 1], ["H2", 1, 0, 1, 1, 1],
# ["J2", 1, 1, 0, 0, 1], ["L2", 1, 1, 0, 1, 1], ["N2", 1, 1, 1, 0, 1],
# ["P2", 1, 1, 1, 1, 1], ["B3", 2, 0, 0, 0, 1], ["D3", 2, 0, 0, 1, 1],
# ["F3", 2, 0, 1, 0, 1], ["H3", 2, 0, 1, 1, 1], ["J3", 2, 1, 0, 0, 1],
# ["L3", 2, 1, 0, 1, 1], ["N3", 2, 1, 1, 0, 1], ["P3", 2, 1, 1, 1, 1]]
Explanation
The steps are as follows for ary3 and most_inner_index = 0.
a = nested_indices(ary3)
#=> [[0, 1, 2], [0, 1, 2]]
first, *rest = a
#=> [[0, 1, 2], [0, 1, 2]]
Ruby applies array decomposition to obtain the following.
first
#=> [0, 1, 2]
rest
#=> [[0, 1, 2]]
Continuing,
b = first.product(*rest)
#=> [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
c = b.map do |indices|
[ary.dig(*indices, most_inner_index), *indices, most_inner_index]
end
#=> [["A1", 0, 0, 0], ["D1", 0, 1, 0], ["G1", 0, 2, 0],
# ["A2", 1, 0, 0], ["D2", 1, 1, 0], ["G2", 1, 2, 0],
# ["A3", 2, 0, 0], ["D3", 2, 1, 0], ["G3", 2, 2, 0]]
See Array#product and Array#dig.
I have a custom model which takes in cropped faces from BlazeFace Model then outputs a prediction of 3 classes.
Before sending them to my custom model I resize the cropped faces to be of shape [1,224,224,3]
Output at every prediction:
Float32Array [
6.522771905936864e-11,
3.698188456857654e-12,
1,
]
Code for resizing the cropped faces and making predictions:
const getPrediction = async tensor => {
if (!tensor) {
console.log("Tensor not found!");
}
// Load both models
const bfModel = await blazeFaceModel;
const returnTensors = true;
const faces = await bfModel
.estimateFaces(tensor, returnTensors)
.catch(e => console.log(e));
// Reshape tensor from rank 3 to rank 4
const tensorReshaped = tensor.reshape([1, 224, 224, 3]);
const scale = {
height: styles.camera.height / tensorDims.height,
width: styles.camera.width / tensorDims.width
};
// Faces is an array of objects
if (!isEmpty(faces)) {
// Setting faces in state
setModelFaces({ faces });
}
//Looping over array of objects in faces
faces.map((face, i) => {
const { topLeft, bottomRight } = face;
const width = Math.floor(
bottomRight.dataSync()[0] - topLeft.dataSync()[0] * scale.width
);
const height = Math.floor(
bottomRight.dataSync()[1] - topLeft.dataSync()[1] * scale.height
);
const boxes = tf
.concat([topLeft.dataSync(), bottomRight.dataSync()])
.reshape([-1, 4]);
// Cropping out faces from original tensor
const crop = tf.image.cropAndResize(
tensorReshaped,
boxes,
[0],
[height, width]
);
// Resize cropped faces to [1,224,224,3]
const alignCorners = true;
const imageResize = tf.image.resizeBilinear(
crop,
[224, 224],
alignCorners
);
makePrediction(imageResize);
});
};
// Make predictions on the tensors
const makePrediction = async image => {
if (!image) {
console.log("No input!");
}
const model = await loadedModel;
const prediction = await model.predict(image, { batchSize: 1 });
if (!prediction || isEmpty(prediction)) {
console.log("Prediction not available");
}
console.log(prediction);
console.log(prediction.dataSync());
};
EDIT
I tried changing the batch size when making predictions to 1 and still the same issue
I tried reconverting the keras model to tfjs format and still the same issue
I tried disposing of the tensor after making a prediction but still there is an error
So i printed out the tensors of the resized faces and its a lot of 0's
Tensor before prediction
Tensor
[[[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
...
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]]]
undefined
Tensor during prediction
Tensor
[[[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
...
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
...,
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]]]
undefined
boxes of tf.image.cropAndResize are normalized coordinates between 0 and 1. Therefore topLeft and bottomRight should be normalized by using [imageWidth, imageHeight]
normalizedTopLeft = topLeft.div(tensor.shape.slice(-3, -2))
// slice will get [h, w] of a tensor of shape [b, h, w, ch] or [h, w, ch]
// do likewise for bottomRight
// use normalizedTopLeft instead of topLeft for cropping
Let's have A like below :
A = np.array([[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 0, 0, 0, 0]])
And now, I have to take all the lines which have a 1 on first column :
A[A[:, 0] > 0]
return: array([[1, 0, 0, 0, 0],
[1, 0, 1, 0, 0]])
And now, I want to modify the first column of the second line ? How can I do it ? Because this is not working :
A[A[:, 0] > 0][1, 1] = 1
A
array([[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 3, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 0, 0, 0, 0]])
My code is more complicated than this one, and so, the condition have to be done in two times like here : (1) > 0 and (2) [1, 1].
I want to initialise a three dimensional ruby array. For a two-dimensional array, I can do
a = Array.new(4){ Array.new(5, 0) }
so I have tried
a = Array.new(4) { Array.new(5, Array.new(6, 0)) }
but if I do a[1][2][3] = 5, it not only sets that element to 5, it sets the corresponding element to 5 in other sub arrays i.e.
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]],
[[0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0], [0, 0, 0, 5, 0, 0]],
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
The issue is that if you pass the value as an argument, you will get an array where each value refers to that same object. You do exactly that with:
Array.new(5, Array.new(6, 0))
You can use Array#*, i.e array multiplication instead:
[[[0] * 6] * 5] * 4
Just use the same syntax (with a block instead of an argument : Array.new(n){...}) for all the dimensions.
a = Array.new(4) { Array.new(5) { Array.new(6, 0) } }
This way, your code will create 20 distincts Array.new(6, 0) sub-sub-arrays instead of replicating the same object 5 times.
require 'pp'
a = Array.new(4) { Array.new(5) { Array.new(6, 0) } }
a[1][2][3] = 5
pp a
# [[[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]],
# [[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 5, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]],
# [[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]],
# [[0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]]]
The following worked properly.
a=Array.new(4){ Array.new(5) { Array.new(6,0) }}
You can use recursion to initialize the elements of a multidimensional array of any dimension.1
Code
def init(n, *rest)
rest.empty? ? Array.new(n, 0) : Array.new(n) { init(*rest) }
end
Examples
dims = [2, 3, 2]
a = init(*dims)
#=> [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
a[0][0][0] = 1
a #=> [[[1, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
dims = [2, 3, 2, 4, 2, 3]
a = init(*dims)
a.flatten.size
#=> 288 (= 2*3*2*4*2*3)
a[0][0][0][0][0][0] = 1
a.flatten.count(1)
#=> 1
Explanation
The steps are as follows.
Suppose, as in the example,
dims = [2, 3, 2]
Then
n, *rest = dims
#=> [2, 3, 2]
n #=> 2
rest
#=> [3, 2]
As rest.empty? #=> false, the method returns
Array.new(2) { init(*[3, 2]) } # (1)
#=> [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
To obtain this result, we execute the block
{ init(*[3, 2]) }
for each of the two elements of the array being constructed. This requires us to compute init([3, 2]) (same as { init(3, 2) }), which is done as follows.
n, *rest = [3, 2]
#=> [3, 2]
n #=> 3
rest
#=> [2]
Again, as rest.empty? #=> false, we return
Array.new(3) { init(*[2]) } # (2)
#=> [[0, 0], [0, 0], [0, 0]]
to expression (1) above. For each of the 3 elements of this array we execute the block
{ init(*[2]) }
This requires us to compute init([2]), which is done as follows.
n, *rest = [2]
#=> [2]
n #=> 2
rest
#=> []
This time, since rest.empty? #=> true, we compute and return
Array.new(2, 0)
#=> [0, 0]
to expression (2) above.
1 Yes, there's no such thing as a "multidimensional array" in Ruby, but I expect readers to know what I mean. The alternative is something like "...of an array containing nested arrays of equal size with any number of levels of nesting", but even that is incomplete as it fails to exclude, for example, [[1, [2,3]], [4,5]]. It would be helpful if Ruby had a name for such objects.
I was trying this simple line of assigning codes to a structured array in numpy, I am not quiet sure, but something wrong happens when I assign a matrix to a sub_array in a structured array I created as follows:
new_type = np.dtype('a3,(2,2)u2')
x = np.zeros(5,dtype=new_type)
x[1]['f1'] = np.array([[1,1],[1,1]])
print x
Out[143]:
array([('', [[0, 0], [0, 0]]), ('', [[1, 0], [0, 0]]),
('', [[0, 0], [0, 0]]), ('', [[0, 0], [0, 0]]),
('', [[0, 0], [0, 0]])],
dtype=[('f0', '|S3'), ('f1', '<u2', (2, 2))])
Shouldn't the second field of the subarray equals at this stage
[[1,1],[1,1]]
I think you want to set things slightly differently. Try:
x['f1'][1] = np.array([[1,1],[1,1]])
which results in:
In [43]: x = np.zeros(5,dtype=new_type)
In [44]: x['f1'][1] = np.array([[1,1],[1,1]])
In [45]: x
Out[45]:
array([('', [[0, 0], [0, 0]]), ('', [[1, 1], [1, 1]]),
('', [[0, 0], [0, 0]]), ('', [[0, 0], [0, 0]]),
('', [[0, 0], [0, 0]])],
dtype=[('f0', '|S3'), ('f1', '<u2', (2, 2))])
This is not to say that this isn't strange behavior though since both x['f1'][1] and x[1]['f1'] print the same results, but clearly are different:
In [51]: x['f1'][1]
Out[51]:
array([[1, 1],
[1, 1]], dtype=uint16)
In [52]: x[1]['f1']
Out[52]:
array([[1, 1],
[1, 1]], dtype=uint16)
In [53]: x[1]['f1'] = 2
In [54]: x
Out[54]:
array([('', [[0, 0], [0, 0]]), ('', [[2, 1], [1, 1]]),
('', [[0, 0], [0, 0]]), ('', [[0, 0], [0, 0]]),
('', [[0, 0], [0, 0]])],
dtype=[('f0', '|S3'), ('f1', '<u2', (2, 2))])
In [55]: x['f1'][1] = 3
In [56]: x
Out[56]:
array([('', [[0, 0], [0, 0]]), ('', [[3, 3], [3, 3]]),
('', [[0, 0], [0, 0]]), ('', [[0, 0], [0, 0]]),
('', [[0, 0], [0, 0]])],
dtype=[('f0', '|S3'), ('f1', '<u2', (2, 2))])
I'd have to think about it a bit more to figure out exactly what is going on.