I have a loop that adds elements to a 1d array:
for i in range(0, 1000):
fvector[0, i] = function_value
after the loop finishes, I have a 1 x 1000 vector that I want to store in a multi-dimensional array fmatrix, which is 50 x 1000. I managed to do this using a loop and copying each element individually - but it is very slow. I've then tried to use slice to copy the whole vector in one go after the loop and then be ready to copy next vector at the next column. How do I make it go to the next column? I've tried:
s=slice([i], None)
fmatrix[s] = fvector
and various combinations for s, but I get error messages about setting an array element with a sequence, or invalid syntax.
I know this should be straight forward but I'm very new to python, numpy and arrays :-(
Try this. Allocate the matrix, here zero-initialized for effect:
>>> import numpy as np
>>> fmatrix = np.zeros((50, 1000))
Then index into it to obtain fvector:
>>> fvector = fmatrix[0]
Then assign to fvector's elements:
>>> for i in xrange(1000):
... fvector[i] = i
If you now inspect fmatrix[0], the first row of fmatrix, you'll find that it has been assigned to in the previous loop. That's because the NumPy row indexing creates fvector as a view on fmatrix's first row. This saves you a copy.
fvector has shape (1,1000). That's a 2D array, even if one axis has length 1.
You can slice it down to a 1D array with fvector[0,:]. This gives the first row.
fmatrix has shape (50,1000). You can slice it down to a 1D array with fmatrix[i,:]. This gives the ith row.
So to assign the values in the first row of fvector to the ith row of fmatrix:
fmatrix[i,:] = fvector[0,:]
Perhaps however there is no need for fvector to be a 2D array? Perhaps just make it a 1D array to begin with:
fvector = np.empty(1000)
for i in range(0, 1000):
fvector[i] = function_value
and then you could do the assignment with
fmatrix[i,:] = fvector
Related
I have a 3D array that looks like this:
edges = round(rand(20,20,20)));
I then create a random list of indices as follows:
indices = floor(rand(10000,3)*(19))+1;
So if I try to use the first row of the indices 2D array to access an element in the edges array, I do:
>>> edges(indices(1,1),indices(1,2),indices(1,3))
>>> ans = 1
I figured, if I wanted to get the value of edges at all of the index positions, I could do
>>> edges(indices)
but that returns an 10000 by 3 matrix. I would expect a 10000 by 1 matrix with values of edges at positions specified by each row of indices. What is going on here, and is there a way to get the values I want without using any for loops?
Yes. Use a single index into edges instead of 3:
edges = round(rand(20,20,20));
indices = floor(rand(10000,1)*(20^3-1))+1;
edges(indices)
You should use randi() instead of round(rand()) as well, because round(5*rand())+1 will give you fewer 1s and 6s than 2s, 3s, 4s, 5s.
edges = randi(2,20,20,20)-1;
indices = randi(20^3,10000,1);
edges(indices)
I am working with N-dimensional array and have a problem with the array indexing. I have a task to find an (N-1)-dimensional array in the middle N-dimensional array.
Let me explain in detail with 3D array. A is a 3-dimensional array that has split into groups. In each group, there are b - number of 2-dimensional arrays in the group. I have simulated it as:
b=5;
A=rand(2,2,20);
groups = reshape(A, size(A,1), size(A,2),b, []);
groups is 4-dimensional array, the 4-th dimension is a number of groups ( here it 4).
To find a middle in each group I have added the following loop:
for ii=1:size(groups,4) % Loop over all groups/slices
middle(:,:,ii) = groups(:,:,(w-1)/2+1,ii); % 1 2 3 4 5 : the middle is 3
end
middle is 3-dimensional array that collects middle array in each group.
As you see in my example I have used b=5( odd number). My problem is with even number b.
I have tried to implement it as ( rewrite the loop above);
l=rem(w,2);
for ii=1:size(groups,4) % Loop over all groups/slices
if l==1
middle(:,:,ii) = groups(:,:,(w-1)/2+1,ii);
else
middle(:,:,ii) = groups(:,:,(w-1)/2,ii);
end
end
But it doesn't work. Matlab gives me an error in the line l=rem(w,2);
Could you suggest to me how I can fix it? Is there another way to implement it?
You should use floor of ceil to round the index to whichever element you want:
middle_index = floor((w-1)/2+1);
Here, the middle of 4 is 2, using ceil you’d pick index 3.
Next, you can extract the arrays in a single indexing operation:
middle = groups(:,:,middle_index,:);
Finally, use squeeze or reshape to get rid of the 3rd index:
middle = squeeze(middle);
I have created a 2D 10x10 Array. using Numpy I want to iterate over the array as efficiently as possible.
However I would like to return the array values. essentially iterating over the 10x10 array 10 times and return a 1x10 array each time.
import datetime
import numpy as np
import random
start = datetime.datetime.now()
a = np.random.uniform(low=-1, high=1, size=(10,10))
print("Time :",datetime.datetime.now() - start)
for x in np.nditer(a):
print(x)
the result is as follows:
0.5738994777717537
0.24988408410910767
0.8391827831682657
0.0015975845830569213
0.54477459840569
0.14091622639476165
-0.36517132895234106
-0.06311125453484467
-0.6572544506539948
...
100 times
However I would expect the result to be:
[0.5738994777717537,
0.24988408410910767,
0.8391827831682657,
0.0015975845830569213,
0.54477459840569,
0.14091622639476165,
-0.36517132895234106,
-0.06311125453484467,
-0.6572544506539948],[...]
...
10 times
Any help would be appreciated!
To directly answer your question, this does exactly what you want:
import numpy as np
a = np.random.uniform(low=-1, high=1, size=(10,10))
print(','.join([str(list(x)) for x in a]))
This will print
[-0.2403881196886386, ... , 0.8518165986395723],[-0.2403881196886386, ... , 0.8518165986395723], ..., [-0.2403881196886386, ... , 0.8518165986395723]
The reason you're printing just the elements of the array is due to the way nditer works. nditer iterates over single elements, even at a multidimensional level, whereas you want to iterate over just the first dimension of the array. For that, for x in a: works as intended.
Edit
Here is a good link if you want to read up on how nditer works: https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#arrays-nditer
If I have a square matrix of arrays such as:
[1,2], [2,3]
[5,9], [1,4]
And I want to get the mean of the first values in the arrays of each row such:
1.5
3
Is this possible in Matlab?
I've used the mean(matrix, 2) command to do this with a matrix of single values, but I'm not sure how to extend this to deal with the arrays.
Get the first elements in all arrays of matrix, then call mean function
mean(matrix(:,:,1))
maybe you need to reshape before call mean
a = matrix(:,:,1);
mean(a(:))
You can apply mean function inside mean function to get the total mean value of the 2D array at index 1. You can do similary with array at index 2. Consider the following snapshot.
After staring at your problem for a long time, it looks like your input is a 3D matrix where each row of your formatting corresponds to a 2D matrix slice. Therefore, in proper MATLAB syntax, your matrix is actually:
M = cat(3, [1,2; 2,3], [5,9; 1,4]);
We thus get:
>> M = cat(3, [1,2; 2,3], [5,9; 1,4])
M(:,:,1) =
1 2
2 3
M(:,:,2) =
5 9
1 4
The first slice is the matrix [1,2; 2,3] and the second slice is [5,9; 1,4]. From what it looks like, you would like the mean of only the first column of every slice and return this as a single vector of values. Therefore, use the mean function and index into the first column for all rows and slices. This will unfortunately become a singleton 3D array so you'll need to squeeze out the singleton dimensions.
Without further ado:
O = squeeze(mean(M(:,1,:)))
We thus get:
>> O = squeeze(mean(M(:,1,:)))
O =
1.5000
3.0000
I have a two arrays within a <1x2 cell>. I want to permute those arrays. Of course, I could use a loop to permute each one, but is there any way to do that task at once, without using loops?
Example:
>> whos('M')
Name Size Bytes Class Attributes
M 1x2 9624 cell
>> permute(M,p_matrix)
This does not permute the contents of the two arrays within M.
I could use something like:
>> for k=1:size(M,2), M{k} = permute(M{k},p_matrix); end
but I'd prefer not to use loops.
Thanks.
This seems to work -
num_cells = numel(M) %// Number of cells in input cell array
size_cell = size(M{1}) %// Get sizes
%// Get size of the numeric array that will hold all of the data from the
%// input cell array with the second dimension representing the index of
%// each cell from the input cell array
size_num_arr = [size_cell(1) num_cells size_cell(2:end)]
%// Dimensions array for permuting with the numeric array holding all data
perm_dim = [1 3:numel(size_cell)+1 2]
%// Store data from input M into a vertically concatenated numeric array
num_array = vertcat(M{:})
%// Reshape and permute the numeric array such that the index to be used
%// for indexing data from different cells ends up as the final dimension
num_array = permute(reshape(num_array,size_num_arr),perm_dim)
num_array = permute(num_array,[p_matrix numel(size_cell)+1])
%// Save the numeric array as a cell array with each block from
%// thus obtained numeric array from its first to the second last dimension
%// forming each cell
size_num_arr2 = size(num_array)
size_num_arr2c = num2cell(size_num_arr2(1:end-1))
M = squeeze(mat2cell(num_array,size_num_arr2c{:},ones(1,num_cells)))
Some quick tests show that mat2cell would prove to be the bottleneck, so if you don't mind indexing into the intermediate numeric array variable num_array and use it's last dimension for an equivalent indexing into M, then this approach could be useful.
Now, another approach if you would like to preserve the cell format would be with arrayfun, assuming each cell of M to be a 4D numeric array -
M = arrayfun(#(x) num_array(:,:,:,:,x),1:N,'Uniform',0)
This seems to perform much better than with mat2cell in terms of performance.
Please note that arrayfun isn't a vectorized solution as most certainly it uses loops behind-the-scenes and seems like mat2cell is using for loops inside its source code, so please do keep all these issues in mind.