How to delete multiple columns from a list of lists - python

test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
If I want to remove column 2, that is [5,7,16] from the list, I know I can use:
[j.pop(1) for j in test_list]
however, if I want to move 2 columns at the same time, that is [5,7,16] and [8,9,20], how can I change the code, so the result is:
The modified mesh after column deletion : [[4, 6], [2, 10], [12, 18]]

Here's one other way:
columns_to_remove = (1,3)
new_object = [[x for i,x in enumerate(l) if i not in columns_to_remove] for l in test_list]
Note that this creates a new object without modifying the original test_list.

test_list = [[4, 5, 6, 8], [2, 7, 10, 9],[12, 16, 18, 20]]
removeIndex = [1,3] # The indices you want to remove
for l in test_list:
for i,v in enumerate(removeIndex):
l.pop(v-i)
print(test_list)

You can try list comprehension with required indices
NOTE: I am not altering the original list, it is creating brand new list
test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
[[i[0], i[2]] for i in test_list]
[[4, 6], [2, 10], [12, 18]]

You can delete multiple columns using a numpy array. Please look at numpy.delete() for documentation.
import numpy as np
test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
a = np.array(test_list)
a = np.delete(a, [1, 3], axis=1)
print (a)
The output will be:
[[ 4 6]
[ 2 10]
[12 18]]
You can also use numpy.delete with slice() if you want to remove a column or a set of columns.
If you want to remove 2nd and 3rd column, you can give:
np.delete(a, slice(1, 3), axis=1)
array([[ 4, 8],
[ 2, 9],
[12, 20]])
If you want to delete 2 and 4th column, you can use slice(start, stop, skip) option as follows:
np.delete(a, slice(1, None,2), 1)
Output of this will be:
array([[ 4, 6],
[ 2, 10],
[12, 18]])
If you want the numpy array to be stored back as a regular list of list, you can always do a.tolist()

You can do it easily with numpy:
import numpy as np
test_list = [[4, 5, 6, 8],
[2, 7, 10, 9],
[12, 16, 18, 20]]
a = np.array(test_list)
a = np.delete(a, [1,3], axis=1)
print(a)
#output:
[[ 4 6]
[ 2 10]
[12 18]]

Related

flatten list of numpy arrays while keeping inner arrays

l = [np.array([[1,2],[3,4]]), np.array([5,6]), np.array([[7,8],[9,10],[11,12]])]
I'm trying to flatten this list of arrays but keeping the inner arrays:
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]
I tried itertools.chain, np.concatenate, np.flatten but none of these options give the output above
Your arrays have different numbers of dimensions, you need to ensure they all are 2D:
out = np.concatenate([x[None,:] if x.ndim == 1 else x for x in l])
output:
array([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 8],
[ 9, 10],
[11, 12]])
or with itertools.chain with a list output:
from itertools import chain
list(chain.from_iterable([x.tolist()] if x.ndim == 1 else x.tolist()
for x in l))
output: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]
You haven't provided your desired output. But, as I understood, you are looking for this:
x = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]
print([n for m in x for n in m])
with output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Please let me know if this is not your desired output.
You basically need to flatten each subarray, concatenate them and finally reshape it.
np.concatenate(list(map(np.ravel, l))).reshape(-1, 2)
output:
array([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 8],
[ 9, 10],
[11, 12]])

How to slice tensorflow tensor differently for each row at once?

I have simple tensor
a = tf.constant([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]])
and want to slice it, but I need to do it differently for each of the rows. This slice operation is described by another tensor
b = tf.constant([[0, 1], [2, 4], [2, 5]])
It means that from the first row of tensor a I need elements from 0 to 1, from the second row from 2 to 4 and so on. So the final final result will be
[
[1],
[8, 9],
[13, 14, 15]
]
My first idea was to fill ranges between begin and end of a slice, but unfortunately, doing it with map_fn is not possible because result's rows have different lengths.
Does anyone know how to do such operation?
Basically we have two arrays to iterate. One with actual data, other with range to return.
Therefore, zip function can help iterate over elements from multiple arrays one by one.
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]])
b = tf.constant([[0, 1], [2, 4], [2, 5]])
# As you iterate, provided a and b have same length
# [1, 2, 3, 4, 5] sliced as [0:1]
# [6, 7, 8, 9, 10] sliced as [2:4]
# [11, 12, 13, 14, 15] sliced as [2:5]
[data.numpy().tolist()[start:end] for data, (start, end) in zip(a,b)]
Output:
[[1], [8, 9], [13, 14, 15]]
If the size of b is known at graph compile time, then you can slice each row separately.
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]])
b = tf.constant([[0, 1], [2, 4], [2, 5]])
r = []
for i in range(3):
bi = b[i]
r.append(a[i][bi[0]: bi[1]])
print(r)

Concatenate arrays by column in python

I have a list of arrays, where each array is a list of lists. I want to turn this into a single array with all the columns. I've tried using for loops to get this done, but it feels like it should be doable in list comprehension. Is there a nice one-liner that will do this?
Example Input: [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
Desired Output: [[1,2,7,8],[3,4,9,10],[5,6,11,12]]
Note: Example only has two arrays in the main list, but my actual data has much more, so I'm looking for something that works for N subarrays.
Edit:
Example trying to solve this
Works for two but doesn't generalize:
[input[0][i]+input[1][i] for i in range(len(input[0]))]
These don't work, but show the idea:
[[element for table in input for element in row] for row in table]
[[*imput[j][i] for j in range(len(input))] for i in range(len(input[0]))]
Edit: Selected answer that uses only list comprehension and zip, but all answers (as of now) work, so use whichever fits your style/use case best.
You can generalize this from the standard list flattening pattern and zip:
>>> L = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
>>> list([y for z in x for y in z] for x in zip(*L))
[[1, 2, 7, 8], [3, 4, 9, 10], [5, 6, 11, 12]]
>>> L = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]],[[13,14],[15,16],[17,18]]]
>>> list([y for z in x for y in z] for x in zip(*L))
[[1, 2, 7, 8, 13, 14], [3, 4, 9, 10, 15, 16], [5, 6, 11, 12, 17, 18]]
Here is one way of doing it:
initial = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]
output = [a+b for a, b in zip(*initial)]
print(output)
If you have more lists, this also works:
import itertools
initial = [[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]],[[13,14],[15,16],[17,18]]]
output = [list(itertools.chain.from_iterable(values)) for values in zip(*initial)]
print(output)
If you don't mind it is a tuple in the list.You could also try:
from itertools import chain
a = [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]], [[13, 14], [15, 16], [17, 18]]]
output = list(map(list, map(chain.from_iterable, zip(*a))))
# [[1, 2, 7, 8, 13, 14], [3, 4, 9, 10, 15, 16], [5, 6, 11, 12, 17, 18]]
This would do it, I named your input first:
[*map(lambda x: list(i for s in x for i in s), zip(*first))]
[[1, 2, 7, 8], [3, 4, 9, 10], [5, 6, 11, 12]]

How to loop through a nested numpy array to obtain column-wise values

I have an input numpy array as follows:
import numpy as np
my_array = [
np.array([[[1, 10]],
[[2, 11]]], dtype=np.int32),
np.array([[[3, 12]],
[[4, 13]],
[[5, 14]]], dtype=np.int32),
np.array([[[6, 15]],
[[7, 16]],
[[8, 17]]], dtype=np.int32)
]
I want to get two arrays (1 for each column) so that:
array1 = [1, 2, 3, 4, 5, 6, 7 ,8]
array2 = [10, 11, 12, 13, 14, 15, 16, 17]
I tried with a list comprehension but it didn't work:
[col[:] for col in my_array]
You can loop through the arrays and append to the new ones:
array1 = []
array2 = []
for array in my_array:
for nested_array in array:
# nested_array is of form [[ 1 10]] here, you need to index it
# first with [0] then with the element you want to access [0] or [1]
array1.append(nested_array[0][0])
array2.append(nested_array[0][1])
You just have to think about the structure of the input data and how to get the values you need in the order that you need.
The output:
>>> array1
[1, 2, 3, 4, 5, 6, 7, 8]
>>> array2
[10, 11, 12, 13, 14, 15, 16, 17]
You can try this:
>>> from numpy import array
>>> import numpy as np
>>> my_array = [array([[[1, 10]],
[[2, 11]]], dtype='int32'), array([[[3, 12]],
[[4, 13]],
[[5, 14]]], dtype='int32'), array([[[6, 15]],
[[7, 16]],
[[8, 17]]], dtype='int32')]
# One way
>>> np.concatenate(my_array,axis=0)[...,0] # [...,1] would give the other one
array([[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8]], dtype=int32)
# Other way:
>>> np.concatenate(my_array,axis=0)[...,0].reshape(-1,) # [...,1].reshape(-1,0) would be the other one
array([1, 2, 3, 4, 5, 6, 7, 8], dtype=int32)

Replacing a vertical sublist in a list of lists

This question is an extension to this question.
I'm representing a two-dimensional array using list of lists, L, say:
[ [1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4] ]
For a given sub-list, say [9, 99], I want to replace a specific sub-list in the "2-D" list by this sublist using something intuitive like:
L[1][0:2] = sublist
# which updates `L` to:
[ [1, 2, 3, 4],
[1, 9, 99, 4],
[1, 2, 3, 4],
[1, 2, 3, 4] ] # not in this format, but written like this for clarity
This works for horizontal replacements, but not for vertical replacements since, as we can't slice to separate lists like this: L[0:2][0]. If I had to use this slicing system, I could transpose L (Transpose list of lists), then use this slicing method, then transpose it back. But that's not efficient, even for the sake of simplicity.
What would be an efficient way to replicate L[0:2][0] and get this output?
[ [1, 2, 3, 4],
[1, 9, 3, 4],
[1, 99, 3, 4],
[1, 2, 3, 4] ]
Note: Assume len(sublist) <= len(L), for vertical replacements (which is the focus of this question).
Looping approach:
def replaceVert(al : list, repl:list, oIdx:int, iIdx:int):
for pos in range(len(repl)):
al[oIdx+pos][iIdx] = repl[pos]
a = [ [1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16] ]
print(a) # [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
replaceVert(a,['ä','ü'],2,2) # this is a one liner ;)
print(a) # [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 'ä', 12], [13, 14, 'ü', 16]]
Transpose/slice/transpose approach:
I overread the mentioning of "no transposing". This is using transpose, change, transpose method with slicing which is not wanted by the Q. It is a answer for the title of this question, so I decided to leave it in for future people search SO and stumble over this Q:
a = [ [1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16] ]
b = list(map(list,zip(*a))) # will make [ [1,5,9,13], ... ,[4,8,12,16]]
b[1][0:2]=['a','b'] # replaces what you want here (using a and b for clarity)
c = list(map(list,zip(*b))) # inverts b back to a's form
print(a)
print(b)
print(c)
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] # a
[[1, 5, 9, 13], ['a', 'b', 10, 14], [3, 7, 11, 15], [4, 8, 12, 16]] # b replaced
[[1, 'a', 3, 4], [5, 'b', 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] # c
Timing 4x4 list, 2 replaces:
setuptxt = """
def replaceVert(al : list, repl:list, oIdx:int, iIdx:int):
for pos in range(len(repl)):
al[oIdx+pos][iIdx] = repl[pos]
a = [ [1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16] ]
"""
zipp = """b = list(map(list,zip(*a)))
b[1][0:2]=['a','b']
c = list(map(list,zip(*b)))
"""
import timeit
print(timeit.timeit("replaceVert(a,['ä','ü'],2,2)",setup = setuptxt))
print(timeit.timeit(stmt=zipp, setup=setuptxt))
Output:
looping: 12.450226907037592
zipping: 7.50479947070815
The method wit ZIPPing (transpose/slice/transpose) needs roughly 60% of the time for 4x4 lists.
Bigger list 1000x1000 and ~70 elements replaced:
setuptxt = """
def replaceVert(al : list, repl:list, oIdx:int, iIdx:int):
for pos in range(len(repl)):
al[oIdx+pos][iIdx] = repl[pos]
a = [ [kk for kk in range(1+pp,1000+pp)] for pp in range(1,1000)]
repl = [chr(mm) for mm in range(32,100)]
"""
import timeit
print(timeit.timeit("replaceVert(a,repl,20,5)",number=500, setup = setuptxt))
zipp = """b = list(map(list,zip(*a)))
b[20][5:5+len(repl)]=repl
c = list(map(list,zip(*b)))
"""
print(timeit.timeit(stmt=zipp, setup=setuptxt,number=500))
Output:
looping: 0.07702917579216137
zipping: 69.4807168493871
Looping wins. Thanks #Sphinx for his comment

Categories

Resources