Transpose of a 3d list - python

I have tried this the below mentioned code:
counts=[[[(col.count(i)) for i in range(1,n)] for col in matrix] for matrix in lists]
print(counts)
and the code gives me
[[[1, 1, 1, 1, 0], [1, 1, 1, 0, 1], [1, 1, 0, 1, 1]], [[4, 0, 0, 0, 0], [1, 2, 1, 0, 0], [0, 0, 1, 3, 0]]]
this output
here 3, 5 element list created. I want 5, 3 element list. The output should look like:
[[[1, 1, 1], [1, 0, 1], [1, 1, 0], [1, 1, 1], [0, 1, 1]], [[4, 0, 0], [0, 0, 1], [2, 1, 0], [0, 0, 0], [1, 3, 0]]]
what kind of work should be performed on 'counts' list so that I get this desired output.

you don't really transpose anything as far as i can tell; this is just a reshaping. numpy lets you do that this way:
import numpy as np
lst = [[[1, 1, 1, 1, 0], [1, 1, 1, 0, 1], [1, 1, 0, 1, 1]],
[[4, 0, 0, 0, 0], [1, 2, 1, 0, 0], [0, 0, 1, 3, 0]]]
arr = np.array(lst)
res = arr.reshape((2, 5, 3))
which gives:
[[[1 1 1]
[1 0 1]
[1 1 0]
[1 1 1]
[0 1 1]]
[[4 0 0]
[0 0 1]
[2 1 0]
[0 0 0]
[1 3 0]]]

Related

Create product of lists, concatenated, in python

import itertools
x = [[0,0],[1,1]]
list(itertools.product(x,x))
produces
[([0, 0], [0, 0]), ([0, 0], [1, 1]), ([1, 1], [0, 0]), ([1, 1], [1, 1])]
But I'm looking for something that produces
[[0, 0, 0, 0], [0, 0, 1, 1], [1, 1, 0, 0], [1, 1, 1, 1]]
itertools.product is giving you that answer, you just have to concatenate the lists
[a + b for a, b in [([0, 0], [0, 0]), ([0, 0], [1, 1]), ([1, 1], [0, 0]), ([1, 1], [1, 1])]]
# [[0, 0, 0, 0], [0, 0, 1, 1], [1, 1, 0, 0], [1, 1, 1, 1]]
In that case, you can easily do without using itertools, using list comprehension:
x = [[0, 0], [1, 1]]
output = [a + b for b in x for a in x]
# [[0, 0, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1], [1, 1, 1, 1]]
the equivalent without list comprehension would be:
output = []
for a in x:
for b in x:
output.append(a + b)
print(output)
You can use np.reshape if you are considering numpy array.
np.reshape(list(itertools.product(x,x)),(4,4))
Out[28]:
array([[0, 0, 0, 0],
[0, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 1, 1]])

get lines where value does not exist

I'm trying to get from 2D list the lines where value = 2 does not exists:
[[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
I've been using:
for i in range(len(list)):
if list[i] in [list]:
# dot stuff
the problem here is that evrytime the code is using the actual line which is list[i] and ignore the the rest even if 2 does not exists on it
hope Iwas clear
Thank you
something like the below
lst = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
lst = [x for x in lst if 2 not in x]
print(lst)
output
[[0, 0, 1, 1], [0, 0, 1, 0]]
Is this your expected output?
[0, 0, 1, 1]
[0, 0, 1, 0]
This is the working code:
a = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
for i in range(len(a)):
if 2 not in a[i]:
print(a[i])

How to create an array of binary digits of given unsigned integer numbers with Numpy?

I have an array of numbers between 0 and 3 and I want to create a 2D array of their binary digits.
in the future may be I need to have array of numbers between 0 and 7 or 0 to 15.
Currently my array is defined like this:
a = np.array([[0], [1], [2], [3]], dtype=np.uint8)
I used numpy unpackbits function:
b = np.unpackbits(a, axis=1)
and the result is this :
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1, 1]], dtype=uint8)
As you can see it created a 2d array with 8 items in column while I'm looking for 2 columns 2d array.
here is my desired array:
array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
Is this related to data type uint8 ?
what is your idea?
One way of approaching the problem is to just adapt your b to match your desired output via a simple slicing, similarly to what suggested in #GrzegorzSkibinski answer:
import numpy as np
def gen_bits_by_val(values):
n = int(max(values)).bit_length()
return np.unpackbits(values, axis=1)[:, -n:].copy()
print(gen_bits_by_val(a))
# [[0 0]
# [0 1]
# [1 0]
# [1 1]]
Alternatively, you could create a look-up table, similarly to what suggested in #WarrenWeckesser answer, using the following:
import numpy as np
def gen_bits_by_num(n):
values = np.arange(2 ** n, dtype=np.uint8).reshape(-1, 1)
return np.unpackbits(values, axis=1)[:, -n:].copy()
bits2 = gen_bits_by_num(2)
print(bits2)
# [[0 0]
# [0 1]
# [1 0]
# [1 1]]
which allows for all kind of uses thereby indicated, e.g.:
bits4 = gen_bits_by_num(4)
print(bits4[[1, 3, 12]])
# [[0 0 0 1]
# [0 0 1 1]
# [1 1 0 0]]
EDIT
Considering #PaulPanzer answer the line:
return np.unpackbits(values, axis=1)[:, -n:]
has been replaced with:
return np.unpackbits(values, axis=1)[:, -n:].copy()
which is more memory efficient.
It could have been replaced with:
return np.unpackbits(values << (8 - n), axis=1, count=n)
with similar effects.
You can use the count keyword. It cuts from the right so you also have to shift bits before applying unpackbits.
b = np.unpackbits(a<<6, axis=1, count=2)
b
# array([[0, 0],
# [0, 1],
# [1, 0],
# [1, 1]], dtype=uint8)
This produces a "clean" array:
b.flags
# C_CONTIGUOUS : True
# F_CONTIGUOUS : False
# OWNDATA : True
# WRITEABLE : True
# ALIGNED : True
# WRITEBACKIFCOPY : False
# UPDATEIFCOPY : False
In contrast, slicing the full 8-column output of unpackbits is in a sense a memory leak because the discarded columns will stay in memory as long as the slice lives.
You can truncate b to keep just the columns since the first column with 1:
b=b[:, int(np.argwhere(b.max(axis=0)==1)[0]):]
For such a small number of bits, you can use a lookup table.
For example, here bits2 is an array with shape (4, 2) that holds the bits of the integers 0, 1, 2, and 3. Index bits2 with the values from a to get the bits:
In [43]: bits2 = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
In [44]: a = np.array([[0], [1], [2], [3]], dtype=np.uint8)
In [45]: bits2[a[:, 0]]
Out[45]:
array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
This works fine for 3 or 4 bits, too:
In [46]: bits4 = np.array([[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 0, 1, 1], [0, 1, 0, 0], [
...: 0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 1], [1, 0, 1, 0], [1, 0,
...: 1, 1], [1, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0], [1, 1, 1, 1]])
In [47]: bits4
Out[47]:
array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 1, 1, 0],
[0, 1, 1, 1],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 0, 1],
[1, 1, 1, 0],
[1, 1, 1, 1]])
In [48]: x = np.array([0, 1, 5, 14, 9, 8, 15])
In [49]: bits4[x]
Out[49]:
array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 1, 0, 1],
[1, 1, 1, 0],
[1, 0, 0, 1],
[1, 0, 0, 0],
[1, 1, 1, 1]])

Algorithm to create a binary-like pattern

I have two numbers: n and sp. I want to create a pattern of list elements with sp elements that rotate like binary digits up to n. To elaborate more on the second part, here is an example:
n = 2, sp = 3
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
Similarly:
n = 3, sp = 3
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 2, 0]
[0, 1, 1]
[0, 1, 2]
[0, 2, 1]
[0, 2, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 2, 0]
[1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[1, 2, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 2]
[2, 1, 0]
[2, 2, 0]
[2, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 2, 2]
I wish to maintain the order that I have given in the examples, that is the LSB is assigned first, then the next bit, and so on...
I could not think of any tactic to solve such a problem. All I could figure out is to use sp to create a temporary list of size sp, for instance, if sp == 3, the temp_list can be [0 0 0]. Then we iterate in a manner so that we get the pattern.
There is no constraint on the complexity of the algorithm, although a shorter algorithm would be very great.
One simple way of doing it is:
def get_patterns(n, sp):
ans = []
def _get_patterns(so_far):
if len(so_far) == sp:
ans.append(so_far[:])
return
for i in range(n):
so_far.append(i)
_get_patterns(so_far)
so_far.pop()
_get_patterns([])
return ans
n = 3
sp = 3
assert get_patterns(n, sp) == sorted([
[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0],
[0, 2, 0], [0, 1, 1], [0, 1, 2], [0, 2, 1], [0, 2, 2],
[1, 0, 0], [1, 0, 1], [1, 0, 2], [1, 1, 0],
[1, 2, 0], [1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2],
[2, 0, 0], [2, 0, 1], [2, 0, 2], [2, 1, 0],
[2, 2, 0], [2, 1, 1], [2, 1, 2], [2, 2, 1], [2, 2, 2],
])
I wrote this
n = 4 # base
sp = 2 # length
def fix(num, base):
for j in range(len(num)):
if num[j] == base:
num[j] = 0
num[j+1] += 1
return num
num= [ 0 for _ in range(sp)]
print(num)
for i in range(n**sp -1):
num[0] += 1
num= fix(num, n)
print(num[::-1])

Creating pandas DataFrame from a list of objects and manipulating over these objects

I have a list of 5 matrices:
import numpy as np
import pandas as pd
a=[(np.random.randint(2,size=(2,3))) for i in xrange(5)]
How do I create a pandas DataFrame of 5 records with a single column containing a matrrix for each row?
You can create the dataframe by running :
df= pd.DataFrame({'array':a})
Output :
array
0 [[0, 0, 0], [0, 0, 0]]
1 [[0, 1, 1], [0, 0, 0]]
2 [[1, 0, 0], [0, 1, 1]]
3 [[1, 0, 1], [1, 0, 0]]
4 [[0, 0, 0], [0, 0, 1]]
If you want to apply cumsum over the column you can use apply
df['array']=df['array'].apply(np.cumsum)
output:
array
0 [0, 0, 0, 0, 0, 0]
1 [0, 1, 2, 2, 2, 2]
2 [1, 1, 1, 1, 2, 3]
3 [1, 1, 2, 3, 3, 3]
4 [0, 0, 0, 0, 0, 1]

Categories

Resources