How to change axis of array slice? - numpy-ndarray

I'm fairly new to numpy arrays, so any help will be much appreciated.
I want to get a single slice of an n x m array along the second axis, with the result being an n x 1 array, e.g.
a = np.array([[1, 2, 3],
[4, 5, 6]])
Then I want:
some_function(a, 0) = array([[1], [4]]) # to get slice of a, along index 0
I've tried a[:, 0] which gives array([1, 4]).
And:
np.transpose(a[:, 0])
also gives:
array([1, 4])
Which confuses me.
I'm sure this is really simple but can't find the correct some_function!

So I've solved it with np.reshape:
some_function(a,0) = np.reshape(a[:,0],(2,1))
But this doesn't seem too elegant. Anyone got a neater solution?

Related

Sparse to Dense Matrix reduces its dimension when there are repetitions

I have a set of indices that I want to convert them to encodings. In order to do so :
i = [2, 1, 3, 4]
s = sparse(i, 1:lenght(i), 1)
s = full(s);
This works fine as expected but when the array i = [2, 1, 3, 3]. The full function gives a 3 by 4 matrix instead of 4 by 4. Julia thinks that the last row is unnecessary and deletes it which ,for my case, is not.
Is it possible to create a square matrix by using sparse and full when there are repetitions inside the index array i?
B.R.
Just supply the dimensions you want as additional arguments, e.g.:
s = sparse(i, 1:length(i), 1, 4, 4)
The details are explained in help for sparse.

Julia sparse matrix with random 1's

So I have a size N in julia and I need an NxN sparse matrix with N ones in it, in random places. What would be the best way to go about this?
At first I thought about randomly generating indexes and then setting those numbers to 1 in a sparse matrix but I recently found the sprand functions however I don't understand how to use them correctly or apply them to my problem. I tried using it with my limited understanding and it keeps generating error messages. Help is of course always greatly appreciated :)
Inspired by #DanGetz comment above, the following solution is a one-line function using randperm. I deleted the original answer as it was not very helpful.
sparseN(N) = sparse(randperm(N), randperm(N), ones(N), N, N)
This is also incredibly fast:
#time sparseN(10_000);
0.000558 seconds (30 allocations: 782.563 KiB)
A sparse matrix of dimension (N rows)x(M columns) has at most NxM components that can be indexed using the K=[0,N*M) integer set. For any k in K you can retrieve element indices (i,j) thanks to a Euclidean division k = i + j*N (here column major layout).
To randomly sample n elements of K (without repetition), you can use Knuth algorithm "Algorithm S (Selection sampling technique)" 3.4.2, in its book Vol2., seminumerical-Algorithms
In Julia:
function random_select(n::Int64,K::Int64)
#assert 0<=n<=K
sample=Vector{Int64}(n)
t=Int64(0)
m=Int64(0)
while m<n
if (K-t)*rand()>=n-m
t+=1
else
m+=1
sample[m]=t
t+=1
end
end
sample
end
The next part simply retrieves the I,J indices to create the sparse matrix from its coordinate form:
function create_sparseMatrix(n::Int64,N::Int64,M::Int64)
#assert (0<=N)&&(0<=M)
#assert 0<=n<=N*M
nonZero = random_select(n,N*M)
# column major: k=i+j*N
I = map(k->mod(k,N),nonZero)
J = map(k->div(k,N),nonZero)
sparse(I+1,J+1,ones(n),N,M)
end
Usage example: a 4x5 sparse matrix with 3 nonzero (=1.0) at random positions:
julia> create_sparseMatrix(3,4,5)
4×5 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[4, 1] = 1.0
[3, 2] = 1.0
[3, 3] = 1.0
Border case tests:
julia> create_sparseMatrix(0,4,5)
4×5 SparseMatrixCSC{Float64,Int64} with 0 stored entries
julia> create_sparseMatrix(4*5,4,5)
4×5 SparseMatrixCSC{Float64,Int64} with 20 stored entries:
[1, 1] = 1.0
[2, 1] = 1.0
[3, 1] = 1.0
[4, 1] = 1.0
⋮
[4, 4] = 1.0
[1, 5] = 1.0
[2, 5] = 1.0
[3, 5] = 1.0
[4, 5] = 1.0
Insisting on a one-line-ish solution:
using StatsBase
sparseones(N,M,K) = sparse(
(x->(first.(x).+1,last.(x).+1))(divrem.(sample(0:N*M-1,K,replace=false),M))...,
ones(K),N,M
)
Giving:
julia> sparseones(3,4,5)
3×4 SparseMatrixCSC{Float64,Int64} with 5 stored entries:
[1, 1] = 1.0
[2, 1] = 1.0
[3, 3] = 1.0
[2, 4] = 1.0
[3, 4] = 1.0
This method is essentially the same as the earlier answer with the advantage of re-using existing sample and being much shorter. It is even faster on larger matrices.

How to vectorize getting sub arrays from numpy array using indexing arrays

I want to get a numpy array of sub arrays from a base array using some type of indexing arrays (style/format of indexing arrays open for suggestions). I can easily do this with a for loop, but wondering if there is a clever way to use numpy broadcasting?
Constraints: Sub-arrays are guaranteed to be the same size.
up_idx = np.array([[0, 0],
[0, 2],
[1, 1]])
lw_idx = np.array([[2, 2],
[2, 4],
[3, 3]])
base = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
samples = []
for index in range(up_idx.shape[0]):
up_row = up_idx[index, 0]
up_col = up_idx[index, 1]
lw_row = lw_idx[index, 0]
lw_col = lw_idx[index, 1]
samples.append(base[up_row:lw_row, up_col:lw_col])
samples = np.array(samples)
print(samples)
> [[[ 1 2]
[ 5 6]]
[[ 3 4]
[ 7 8]]
[[ 6 7]
[10 11]]]
I've tried:
vector_s = base[up_idx[:, 0]:lw_idx[:, 1], up_idx[:, 1]:lw_idx[:, 1]]
But that was just nonsensical it seems.
I don't think there is a fast way to do this in general via numpy broadcasting operations – for one thing, the way you set up the problem there is no guarantee that the resulting sub-arrays will be the same shape, and thus able to fit into a single output array.
The most succinct and efficient way to solve this is probably via a list comprehension; e.g.
result = np.array([base[i1:i2, j1:j2] for (i1, j1), (i2, j2) in zip(up_idx, lw_idx)])
Unless your base array is very large, this shouldn't be much of a bottleneck.
If you have different problem constraints (i.e. same size slice in every case) it may be possible to come up with a faster vectorized solution based on fancy indexing. For example, if every slice is of size two (as in your example above) then you can use fancy indexing like this to obtain the same result:
i, j = up_idx.T[:, :, None] + np.arange(2)
result = base[i[:, :, None], j[:, None]]
The key to understanding this fancy indexing is to realize that the result follows the broadcasted shape of the index arrays.

How to achieve all elements swapped in an array

I have an ordered array which contain 1 to 1000000 elements.
I want to achieve an array such that the elements in the array are swapped with its next element.For instance if we assume the array elements are
[1,2,3,4,5,6]
I want to return an array with elements as
[2,1,4,3,6,5]
How do I achieve this in ruby for 100000 such elements? Can anyone guide me?
a = [1,2,3,4,5,6]
a.each_slice(2).map{|inner_a| inner_a.reverse}.flatten
# => [2, 1, 4, 3, 6, 5]
Description:
a.each_slice(2)returns an enumerator (#<Enumerator: [1, 2, 3, 4, 5, 6]:each_slice(2)>) with two element couples from your array. To see try a.each_slice(2).to_a. This returns [[1, 2], [3, 4], [5, 6]] with I only have to flatten for your expected result.
See also the first comment if you prefer a shorter notation of it.
Assuming you want to use a minimum amount of memory (since you chose a large array), and assuming the result is to be a mutated array (i.e. not a new array, but a change to the existing array) and finally assuming a is always an even number of elements...
a.each_index{|x| a[x], a[x+1] = a[x+1], a[x] if x.even?}
Possibly more performant...
(0...a.size).step(2) {|x| a[x], a[x+1] = a[x+1], a[x]}
You can try this.
arr = (1..100000).to_a
arr.each_with_index.each_slice(2){|(_,i), (_,j)| arr[i], arr[j] = arr[j], arr[i]}

Generate random numbers with exceptions

I want to generate a pair of random numbers withing a range but also the pair must not be contained in an array of pairs I have, so you can basically think of the task as generating a random pair with exceptions. I know you can do it with a loop but I've been told it's possible with only one level of indentation. I've been searching around for something similar, so far no results. Your help would be much obliged, cheers.
Very inefficient, but expressive and short:
range = (1..3).to_a
undesired_pairs = [[1, 1], [2, 2], [3, 3]]
(range.product(range) - undesired_pairs).sample # => [1, 3]
Another solution: Create a random pair until you have a result, that is not in undesired_pairs:
undesired_pairs = [[1, 1], [2, 2], [3, 3]]
until ! undesired_pairs.include?(hit =[rand(3)+1,rand(3)+1])
end
p hit

Resources