Slicing lists containing lists [duplicate] - python

This question already has answers here:
Slicing list of lists in Python
(6 answers)
Closed 2 years ago.
I have a list containing 3 lists:
V1 = [0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3]
V2 = [4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7]
V3 = [8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11]
V = [V1,V2,V3]
I would like to slice V so that the indexes 4:7 of V1,V2 and V3 are selected and put into list Z. I tried doing it like this:
Z = V[:,4:7]
But I get the error:
TypeError: list indices must be integers or slices, not tuple
How do I correct this?

You need to use numpy to get an array that is sliceable in multi-dimension
V = np.array([V1, V2, V3])
Z = V[:, 4:7]
# V
[[ 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3]
[ 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7]
[ 8 8 8 8 9 9 9 9 10 10 10 10 11 11 11 11]]
# Z
[[1 1 1]
[5 5 5]
[9 9 9]]

Your code will work if it was numpy.array
V1 = [0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3]
V2 = [4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7]
V3 = [8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11]
V = [V1,V2,V3]
import numpy as np
spam = np.array(V)
print(spam[:,4:7])
output
[[1 1 1]
[5 5 5]
[9 9 9]]
without numpy you can use list comprehension:
eggs = [item[4:7] for item in V]
print(eggs)
output
[[1, 1, 1], [5, 5, 5], [9, 9, 9]]

You cannot simply slice a sublist, but you can iterate over each sublist and slice them one by one:
V1 = [0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3]
V2 = [4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7]
V3 = [8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11]
V = [V1, V2, V3]
Z = []
for sublist in V:
Z.append(sublist[4:7])
Or use numpy as suggested in other answers.

Related

Convert a dataframe to an array

I have a dataframe like the following.
i
j
element
0
0
1
0
1
2
0
2
3
1
0
4
1
1
5
1
2
6
2
0
7
2
1
8
2
2
9
How can I convert it to the 3*3 array below?
1
2
3
4
5
6
7
8
9
Assuming that the dataframe is called df, one can use pandas.DataFrame.pivot as follows, with .to_numpy() (recommended) or .values as follows
array = df.pivot(index='i', columns='j', values='element').to_numpy()
# or
array = df.pivot(index='i', columns='j', values='element').values
[Out]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=int64)
If you transform your dataframe into three lists where the first is containing "i" values, the second - j and the third is data, you can create NumPy array "manually":
i, j, v = zip(*[x for x in df.itertuples(index=False, name=None)])
arr = np.zeros(df.shape)
arr[i, j] = v

pandas create a DataFrame by multiplying every element in a list with every other element

I need to populate a dataframe with a matrix built from a single list, but the math and python syntax are beyond me. I essentially need to perform some math operations as if the same list were both the rows and the columns.
So it should look something like this....
#Input
list = [1,2,3,4]
create a matrix using some math on the list, like matrix[i,j] = list[i] * list[j]
#output
np.matrix([[1,2,3,4], [2,4,6,8], [3,6,9,12], [4,8,12,16]])
df = pd.dataframe[np.matrix]
Broadcasted multiplication will work here:
arr = np.array([1, 2, 3, 4])
pd.DataFrame(arr * arr[:,None])
0 1 2 3
0 1 2 3 4
1 2 4 6 8
2 3 6 9 12
3 4 8 12 16
Alternatively, most numpy arithmetic functions define an .outer unfunc:
pd.DataFrame(np.multiply.outer(arr, arr))
0 1 2 3
0 1 2 3 4
1 2 4 6 8
2 3 6 9 12
3 4 8 12 16
data = [1,2,3,4]
Nested for loops would work:
import numpy as np
a = []
for n in data:
row = []
for m in data:
math = some_operation_on(m,n)
row.append(math)
a.append(row)
a = np.array(a)
For simple operations like your example use numpy.meshgrid.
In [21]: a = [1,2,3,4]
In [22]: x,y = np.meshgrid(a,a)
In [23]: x*y
Out[23]:
array([[ 1, 2, 3, 4],
[ 2, 4, 6, 8],
[ 3, 6, 9, 12],
[ 4, 8, 12, 16]])

Shuffle "coupled" elements in python array

Let's say I have this array:
np.arange(9)
[0 1 2 3 4 5 6 7 8]
I would like to shuffle the elements with np.random.shuffle but certain numbers have to be in the original order.
I want that 0, 1, 2 have the original order.
I want that 3, 4, 5 have the original order.
And I want that 6, 7, 8 have the original order.
The number of elements in the array would be multiple of 3.
For example, some possible outputs would be:
[ 3 4 5 0 1 2 6 7 8]
[ 0 1 2 6 7 8 3 4 5]
But this one:
[2 1 0 3 4 5 6 7 8]
Would not be valid because 0, 1, 2 are not in the original order
I think that maybe zip() could be useful here, but I'm not sure.
Short solution using numpy.random.shuffle and numpy.ndarray.flatten functions:
arr = np.arange(9)
arr_reshaped = arr.reshape((3,3)) # reshaping the input array to size 3x3
np.random.shuffle(arr_reshaped)
result = arr_reshaped.flatten()
print(result)
One of possible random results:
[3 4 5 0 1 2 6 7 8]
Naive approach:
num_indices = len(array_to_shuffle) // 3 # use normal / in python 2
indices = np.arange(num_indices)
np.random.shuffle(indices)
shuffled_array = np.empty_like(array_to_shuffle)
cur_idx = 0
for idx in indices:
shuffled_array[cur_idx:cur_idx+3] = array_to_shuffle[idx*3:(idx+1)*3]
cur_idx += 3
Faster (and cleaner) option:
num_indices = len(array_to_shuffle) // 3 # use normal / in python 2
indices = np.arange(num_indices)
np.random.shuffle(indices)
tmp = array_to_shuffle.reshape([-1,3])
tmp = tmp[indices,:]
tmp.reshape([-1])

List Comprehension Nested Loop, Multiple Operations

Given a list like so:
[[1,2,3],[4,5,6],[7,8,9]]
I'm trying to get my output to look like this, with using only a list comprehension:
1 2 3
4 5 6
7 8 9
Right now I have this:
[print(x,end="") for row in myList for x in row]
This only outputs:
1 2 3 4 5 6 7 8 9
Is there a way to have it break to a new line after it processes each inner list?
You could do like the below.
>>> l = [[1,2,3],[4,5,6],[7,8,9]]
>>> for i in l:
print(' '.join(map(str, i)))
1 2 3
4 5 6
7 8 9
You can do as follows:
print("\n".join(" ".join(map(str, x)) for x in mylist))
Gives:
1 2 3
4 5 6
7 8 9
>>> l = [[1,2,3],[4,5,6],[7,8,9]]
>>> for line in l:
print(*line)
1 2 3
4 5 6
7 8 9
A good explanation of the star in this answer. tl;dr version: if line is [1, 2, 3], print(*line) is equivalent to print(1, 2, 3), which is distinct from print(line) which is print([1, 2, 3]).
I agree with Ashwini Chaudhary that using list comprehension to print is probably never the "right thing to do".
Marcin's answer is probably the best one-liner and Andrew's wins for readability.
For the sake of answering the question that was asked...
>>> from __future__ import print_function # python2.x only
>>> list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [print(*x, sep=' ') for x in list]
1 2 3
4 5 6
7 8 9
[None, None, None]
Try this:
print("\n".join([' '.join([str(val) for val in list]) for list in my_list]))
In [1]: my_list = [[1,2,3],[4,5,6],[7,8,9]]
In [2]: print("\n".join([' '.join([str(val) for val in list]) for list in my_list]))
1 2 3
4 5 6
7 8 9

Python: Shrink/Extend 2D arrays in fractions

There are 2D arrays of numbers as outputs of some numerical processes in the form of 1x1, 3x3, 5x5, ... shaped, that correspond to different resolutions.
In a stage an average i.e., 2D array value in the shape nxn needs to be produced.
If the outputs were in consistency of shape i.e., say all in 11x11 the solution was obvious, so:
element_wise_mean_of_all_arrays.
For the problem of this post however the arrays are in different shapes so the obvious way does not work!
I thought it might be some help by using kron function however it didn't. For example, if array is in shape of 17x17 how to make it 21x21. So for all others from 1x1,3x3,..., to build a constant-shaped array, say 21x21.
Also it can be the case that the arrays are smaller and bigger in shape compared to the target shape. That is an array of 31x31 to be shruk into 21x21.
You could imagine the problem as a very common task for images, being shrunk or extended.
What are possible efficient approaches to do the same jobs on 2D arrays, in Python, using numpy, scipy, etc?
Updates:
Here is a bit optimized version of the accepted answer bellow:
def resize(X,shape=None):
if shape==None:
return X
m,n = shape
Y = np.zeros((m,n),dtype=type(X[0,0]))
k = len(X)
p,q = k/m,k/n
for i in xrange(m):
Y[i,:] = X[i*p,np.int_(np.arange(n)*q)]
return Y
It works perfectly, however do you all agree it is the best choice in terms of the efficiency? If not any improvement?
# Expanding ---------------------------------
>>> X = np.array([[1,2,3],[4,5,6],[7,8,9]])
[[1 2 3]
[4 5 6]
[7 8 9]]
>>> resize(X,[7,11])
[[1 1 1 1 2 2 2 2 3 3 3]
[1 1 1 1 2 2 2 2 3 3 3]
[1 1 1 1 2 2 2 2 3 3 3]
[4 4 4 4 5 5 5 5 6 6 6]
[4 4 4 4 5 5 5 5 6 6 6]
[7 7 7 7 8 8 8 8 9 9 9]
[7 7 7 7 8 8 8 8 9 9 9]]
# Shrinking ---------------------------------
>>> X = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]]
>>> resize(X,(2,2))
[[ 1 3]
[ 9 11]]
Final note: that the code above easily could be translated to Fortran for the highest performance possible.
I'm not sure I understand exactly what you are trying but if what I think the simplest way would be:
wanted_size = 21
a = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
b = numpy.zeros((wanted_size, wanted_size))
for i in range(wanted_size):
for j in range(wanted_size):
idx1 = i * len(a) / wanted_size
idx2 = j * len(a) / wanted_size
b[i][j] = a[idx1][idx2]
You could maybe replace the b[i][j] = a[idx1][idx2] with some custom function like the average of a 3x3 matrix centered in a[idx1][idx2] or some interpolation function.

Categories

Resources