Recover data from lists in Python - python

I have two lists in python, say A and B.
List A is a list of lists with some integer indexes, for example [[2,3,1,3,2,3,3], [4,2,1,4],[5,4,3,3,3,4,]...] and so on.
List B has the same structure but instead of integers has numpy arrays.
[[array([0, 0]), array([0, 0]), array([0, 1]) ...][[array([0, 0]), array([0, 1])...]...]
These lists are correlated, so each numpy array corresponds to a integer, in other words, the sublists of A and the sublists of B has the same size. For example
[[2,3,3,3,2,4]...]
[[array([0, 0]), array([0, 1]), array([0, 1]), array([0, 1]), array([0, 0]), array([1, 0])]...]
The first integer in the sublist of A, "2" is linked to the first numpy array in the sublist of B.
As you can see there are repeated integers, and in consequence repeated numpy arrays. I want to recover the unique indexes without repeating, and thus their corresponding arrays.
Taking the example above the return of the procedure should be something like this:
[[2,3,4]...]
[[array([0, 0]), array([0, 1]), array([1, 0])]...]
How can I recover the unique elements from list A with their corresponded numpy array in list b?
My first attempt used the numpy.unique function so i can recover list A efficiently, but then I lose the information to recover the information from B. The line was
A = np.array([np.unique(a) for a in A])
TO RECAP
I have the following
import numpy as np
A = [] # PUT A REAL (short) LIST HERE
B = [] # PUT A REAL (short) LIST HERE
uniqueA = np.array([np.unique(a) for a in A])
print uniqueA #prints what I want/dont want
expectA = [1,4] # put what you would expect to get back
#ask additional questions here

First, get unique indices of A, then take them from A and B
import numpy as np
A = [[2,3,1,3,2,3,3], [4,2,1,4]]
B = [[np.zeros(2)]*len(A[0]), [np.zeros(2)]*len(A[1])]
indices = np.array([np.unique(a, True)[1] for a in A])
A = np.array([np.array(arr)[index] for arr, index in zip(A, indices)])
B = np.array([np.array(arr)[index] for arr, index in zip(B, indices)])

Related

Get column indices of row-wise maximum values of a 2D array (with random tie-breaking)

Given a 2D numpy array, I want to construct an array out of the column indices of the maximum value of each row. So far, arr.argmax(1) works well. However, for my specific case, for some rows, 2 or more columns may contain the maximum value. In that case, I want to select a column index randomly (not the first index as it is the case with .argmax(1)).
For example, for the following arr:
arr = np.array([
[0, 1, 0],
[1, 1, 0],
[2, 1, 3],
[3, 2, 2]
])
there can be two possible outcomes: array([1, 0, 2, 0]) and array([1, 1, 2, 0]) each chosen with 1/2 probability.
I have code that returns the expected output using a list comprehension:
idx = np.arange(arr.shape[1])
ans = [np.random.choice(idx[ix]) for ix in arr == arr.max(1, keepdims=True)]
but I'm looking for an optimized numpy solution. In other words, how do I replace the list comprehension with numpy methods to make the code feasible for bigger arrays?
Use scipy.stats.rankdata and apply_along_axis as follows.
import numpy as np
from scipy.stats import rankdata
ranks = rankdata(-arr, axis = 1, method = "min")
func = lambda x: np.random.choice(np.where(x==1)[0])
idx = np.apply_along_axis(func, 1, ranks)
print(idx)
It returns [1 0 2 0] or [1 1 2 0].
The main idea is rankdata calculates ranks of every value in each row, and the maximum value will have 1. func randomly choices one of index whose corresponding value is 1. Finally, apply_along_axis applies the func to every row of arr.
After some advice I got offline, it turns out that randomization of maximum values are possible when we multiply the boolean array that flags row-wise maximum values by a random array of the same shape. Then what remains is a simple argmax(1) call.
# boolean array that flags maximum values of each row
mxs = arr == arr.max(1, keepdims=True)
# random array where non-maximum values are zero and maximum values are random values
random_arr = np.random.rand(*arr.shape) * mxs
# row-wise maximum of the auxiliary array
ans = random_arr.argmax(1)
A timeit test shows that for data of shape (507_563, 12), this code runs in ~172 ms on my machine while the loop in the question runs for 11 sec, so this is about 63x faster.

Iterating through rows in numpy array with one row

For a 2D numpy array A, the loop for a in A will loop through all the rows in A. This functionality is what I want for my code, but I'm having difficulty with the edge case where A only has one row (i.e., is essentially a 1-dimensional array). In this case, the for loop treats A as a 1D array and iterates through its elements. What I want to instead happen in this case is a natural extension of the 2D case, where the loop retrieves the (single) row in A. Is there a way to format the array A such that the for loop functions like this?
Depending on if you declare the array yourself you can do this:
A = np.array([[1, 2, 3]])
Else you can check the dim of your array before iterating over it
B = np.array([1, 2, 3])
if B.ndim == 1:
B = B[None, :]
Or you can use the function np.at_least2d
C = np.array([1, 2, 3])
C = np.atleast_2d(C)
If your array trully is a 2D array, even with one row, there is no edge case:
import numpy
a = numpy.array([[1, 2, 3]])
for line in a:
print(line)
>>> [1 2 3]
You seem to be confusing numpy.array([[1, 2, 3]]) which is a 2D array of one line and numpy.array([1, 2, 3]) which would be a 1D array.
I think you can use np.expand_dims to achieve your goal
X = np.expand_dims(X, axis=0)

Counting occurrences of elements of one array in another array

I want to find frequency of elements of a given one dimensional numpy array (arr1) in another one dimensional numpy array (arr2). The array arr1 contains elements with no repetitions. Also, all elements in arr1 are part of the array of unique elements of arr2
Consider this as an example,
arr1 = np.array([1,2,6])
arr2 = np.array([2, 3, 6, 1, 2, 1, 2, 0, 2, 0])
At present, I am using the following:
freq = np.zeros( len(arr1) )
for i in range( len(arr1) ):
mark = np.where( arr2==arr1[i] )
freq[i] = len(mark[0])
print freq
>>[2, 4, 1]
The aforementioned method gives me the correct answer. But, I want to know if there is a better/more efficient method than the one that I am following.
Here's a vectorized solution based on np.searchsorted -
idx = np.searchsorted(arr1,arr2)
idx[idx==len(arr1)] = 0
mask = arr1[idx]==arr2
out = np.bincount(idx[mask])
It assumes arr1 is sorted. If not so, we got two solutions :
Sort arr1 as the pre-processing step. Since, arr1 is part of unique elements from arr2, this should be a comparatively smaller array and hence an inexpensive sorting operation.
Use sorter arg with searchsorted to compute idx:
sidx = arr1.argsort();
idx = sidx[np.searchsorted(arr1,arr2,sorter=sidx)]

Python numpy convert 2d array in 1d array sorted

I have a 2D numpy array and I want to change this array into a 1D which is sorted. For example:
A = [[1,0,2],
[0,3,0]]
I want this to be like:
B = [3,2,1,0,0,0]
Any idea how I can do this using python modules and not to write a sorting algorithm or anything like that ?
Thanks
Assuming you are looking to sort them in descending order -
In [127]: A
Out[127]: [[1, 0, 2], [0, 3, 0]]
In [128]: B = np.sort(np.array(A).ravel())
In [129]: B[::-1]
Out[129]: array([3, 2, 1, 0, 0, 0])
Basically, it involves three steps: Flatten the array with ravel(), sort it with np.sort and then reverse the indexing for an effect of descending order sorting.
This is my solution:
A = [[1,0,2], [0,3,0]]
B = []
for i in range(len(A)):
for j in range(len(A[i])):
B.append(A[i][j])
B.sort(cmp=None, key=None, reverse=True)
print B
You can see my code running here: http://ideone.com/P8xBPK

Acquiring the Minimum array out of Multiple Arrays by order in Python

Say that I have 4 numpy arrays
[1,2,3]
[2,3,1]
[3,2,1]
[1,3,2]
In this case, I've determined [1,2,3] is the "minimum array" for my purposes, as it is one of two arrays with lowest value at index 0, and of those two arrays it has the the lowest index 1. If there were more arrays with similar values, I would need to compare the next index values, and so on.
How can I extract the array [1,2,3] in that same order from the pile?
How can I extend that to x arrays of size n?
Thanks
Using the python non-numpy .sort() or sorted() on a list of lists (not numpy arrays) automatically does this e.g.
a = [[1,2,3],[2,3,1],[3,2,1],[1,3,2]]
a.sort()
gives
[[1,2,3],[1,3,2],[2,3,1],[3,2,1]]
The numpy sort seems to only sort the subarrays recursively so it seems the best way would be to convert it to a python list first. Assuming you have an array of arrays you want to pick the minimum of you could get the minimum as
sorted(a.tolist())[0]
As someone pointed out you could also do min(a.tolist()) which uses the same type of comparisons as sort, and would be faster for large arrays (linear vs n log n asymptotic run time).
Here's an idea using numpy:
import numpy
a = numpy.array([[1,2,3],[2,3,1],[3,2,1],[1,3,2]])
col = 0
while a.shape[0] > 1:
b = numpy.argmin(a[:,col:], axis=1)
a = a[b == numpy.min(b)]
col += 1
print a
This checks column by column until only one row is left.
numpy's lexsort is close to what you want. It sorts on the last key first, but that's easy to get around:
>>> a = np.array([[1,2,3],[2,3,1],[3,2,1],[1,3,2]])
>>> order = np.lexsort(a[:, ::-1].T)
>>> order
array([0, 3, 1, 2])
>>> a[order]
array([[1, 2, 3],
[1, 3, 2],
[2, 3, 1],
[3, 2, 1]])

Categories