Лучший / быстрый способ удаления столбца из списка Python 2D - PullRequest
0 голосов
/ 03 февраля 2019

У меня есть список списков списков (все списки имеют одинаковый размер) в Python, как это:

A = [[1,2,3,4],['a','b','c','d'] , [12,13,14,15]]

Я хочу удалить некоторые столбцы (i-й элементы всех списков).

Есть ли способ сделать это без for утверждений?

Ответы [ 5 ]

0 голосов
/ 03 февраля 2019

Другой вариант с использованием списка-понимания, с enumerate:

>>> A = [[1,2,3,4],['a','b','c','d'] , [12,13,14,15]]
>>> k = 2
>>> [[x for i, x in enumerate(a) if i != k] for a in A]
[[1, 2, 4], ['a', 'b', 'd'], [12, 13, 15]]

И, да, в нем есть слово for (даже дважды!), Но производительность не должна отличатьсячем для любого другого подхода (хотя numpy может быть быстрее).

0 голосов
/ 03 февраля 2019

Как уже упоминалось, вы не можете сделать это без цикла.Однако, используя встроенные функции, вот функциональный подход, который не использует явно какой-либо цикл:

In [24]: from operator import itemgetter

In [25]: def remove_col(arr, ith):
    ...:     itg = itemgetter(*filter((ith).__ne__, range(len(arr[0]))))
    ...:     return list(map(list, map(itg, arr)))
    ...: 

Демонстрация:

In [26]: remove_col(A, 1)
Out[26]: [[1, 3, 4], ['a', 'c', 'd'], [12, 14, 15]]

In [27]: remove_col(A, 3)
Out[27]: [[1, 2, 3], ['a', 'b', 'c'], [12, 13, 14]]

Обратите внимание, что вместо list(map(list, map(itg, arr))), если вы толькоreturn map(itg, arr) даст ожидаемый результат, но в качестве итератора итераторов вместо списка списков.В этом случае это будет более оптимизированный подход с точки зрения как памяти, так и времени выполнения.

Также, используя циклы, я бы сделал следующее:

In [31]: def remove_col(arr, ith):
    ...:     return [[j for i,j in enumerate(sub) if i != ith] for sub in arr]

Удивительно (нет, если вы верите в силу C :)) для больших массивов функциональный подход еще быстрее.

In [41]: arr = A * 10000

In [42]: %timeit remove_col_functional(arr, 2)
8.42 ms ± 37.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [43]: %timeit remove_col_list_com(arr, 2)
23.7 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

# And if in functional approach you just return map(itg, arr)
In [47]: %timeit remove_col_functional_iterator(arr, 2)
1.48 µs ± 4.71 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
0 голосов
/ 03 февраля 2019

Я думаю, что вы можете сделать это без for, если вы владеете zip (это мой любимый "хак"):

A = [[1, 2, 3, 4], ['a', 'b', 'c', 'd'], [12, 13, 14, 15]]
B = list(zip(*A))
B.pop(i)
C = list(map(list, zip(*B)))

Результат (i = 2):

[[1, 2, 4], ['a', 'b', 'd'], [12, 13, 15]]

Конечно, map является альтернативой пониманию списка:

B = list(map(lambda l: l[:i] + l[i + 1:], A))
0 голосов
/ 03 февраля 2019

numpy может удалить целые столбцы:

import numpy

A = [[1,2,3,4],['a','b','c','d'] , [12,13,14,15]]

na = numpy.array(A)

print(na[:,:-1])   # remove last column
print(na[:,1:])    # remove first column

print(numpy.concatenate((na[:,:2],na[:,3:]),axis=1)) # build from 2 slices: remove third column

результат (ради простоты: все данные были преобразованы в строку, без dtype):

[['1' '2' '3']
 ['a' 'b' 'c']
 ['12' '13' '14']]

[['2' '3' '4']
 ['b' 'c' 'd']
 ['13' '14' '15']]

[['1' '2' '4']
 ['a' 'b' 'd']
 ['12' '13' '15']]
0 голосов
/ 03 февраля 2019

Вы можете легко использовать список понимания и фрагменты :

A = [[1,2,3,4],['a','b','c','d'] , [12,13,14,15]]
k = 1

B = [l[:k]+l[k+1:] for l in A]

print(B) # >> returns [[1, 3, 4], ['a', 'c', 'd'], [12, 14, 15]]
...