簡體   English   中英

將元組列表列表轉換為數組時,如何阻止元組創建第3維?

[英]When turning a list of lists of tuples to an array, how can I stop tuples from creating a 3rd dimension?

我有一個元組的列表(每個相同長度的子列表)(每個相同長度的元組為2)。 每個子列表代表一個句子,而元組是該句子的雙字母組。

當使用np.asarray將其轉換為數組時,python似乎在解釋元組,因為我要求創建第三維。

完整的工作代碼在這里:

import numpy as np 
from nltk import bigrams  

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

bi_grams = []
for sent in arr:
    bi_grams.append(list(bigrams(sent)))
bi_grams = np.asarray(bi_grams)
print(bi_grams)

因此,在將bi_grams轉換為數組之前,它看起來像這樣: [[(1, 2), (2, 3)], [(4, 5), (5, 6)], [(7, 8), (8, 9)]]

上面代碼的輸出:

array([[[1, 2],
        [2, 3]],

       [[4, 5],
        [5, 6]],

       [[7, 8],
        [8, 9]]])

以這種方式將列表列表轉換為數組通常很好,並創建了一個2D數組,但似乎python將元組解釋為添加的維,因此輸出的形狀為(3, 2, 2) ,當位於實際上,我想要並且一直期望(3, 2)的形狀。

我想要的輸出是:

array([[(1, 2), (2, 3)],
       [(4, 5), (5, 6)],
       [(7, 8), (8, 9)]])

形狀為(3, 2)

為什么會這樣? 如何獲得所需形狀/形狀的數組?

對於np.array ,您的元組列表列表與列表列表沒有任何不同。 從頭到尾都是可迭代的。 np.array嘗試創建盡可能高的維度數組。 在這種情況下是3d。

有一些方法可以避免這種情況,並制作一個包含對象的2d數組,其中這些對象是元組之類的東西。 但是,正如評論中指出的那樣,您為什么要這么做?

在最近的SO 問題中 ,我想出了一種將nd數組轉換為(nm)-d形狀的對象數組的方法:

In [267]: res = np.empty((3,2),object)
In [268]: arr = np.array(alist)
In [269]: for ij in np.ndindex(res.shape):
     ...:     res[ij] = arr[ij]
     ...:     
In [270]: res
Out[270]: 
array([[array([1, 2]), array([2, 3])],
       [array([4, 5]), array([5, 6])],
       [array([7, 8]), array([8, 9])]], dtype=object)

但這是數組的二維數組,而不是元組。

In [271]: for ij in np.ndindex(res.shape):
     ...:     res[ij] = tuple(arr[ij].tolist())
     ...:     
     ...:     
In [272]: res
Out[272]: 
array([[(1, 2), (2, 3)],
       [(4, 5), (5, 6)],
       [(7, 8), (8, 9)]], dtype=object)

更好(或者是?)

或者我可以直接索引嵌套列表:

In [274]: for i,j in np.ndindex(res.shape):
     ...:     res[i,j] = alist[i][j]
     ...:     
In [275]: res
Out[275]: 
array([[(1, 2), (2, 3)],
       [(4, 5), (5, 6)],
       [(7, 8), (8, 9)]], dtype=object)

我正在使用ndindex生成(3,2)數組的所有索引。

注釋中提到的結構化數組之所以起作用,是因為對於復合dtype,元組與列表不同。

In [277]: np.array(alist, 'i,i')
Out[277]: 
array([[(1, 2), (2, 3)],
       [(4, 5), (5, 6)],
       [(7, 8), (8, 9)]], dtype=[('f0', '<i4'), ('f1', '<i4')])

從技術上講,雖然不是元組數組。 它只是將數組的元素(或記錄)表示為元組。

在對象dtype數組中,數組的元素是指向列表中元組的指針(至少在Out[275]情況下)。 在結構化數組的情況下,數字以與3d數組相同的方式存儲為數組數據緩沖區中的字節。

這是補充@hpaulj答案的另外兩種方法。 其中之一, frompyfunc方法的擴展性似乎比其他方法好一些,盡管如果我們擺脫循環,hpaulj的預分配方法也不錯。 請參閱以下時間:

import numpy as np
import itertools

bi_grams = [[(1, 2), (2, 3)], [(4, 5), (5, 6)], [(7, 8), (8, 9)]]

def f_pp_1(bi_grams):
    return np.frompyfunc(itertools.chain.from_iterable(bi_grams).__next__, 0, 1)(np.empty((len(bi_grams), len(bi_grams[0])), dtype=object))

def f_pp_2(bi_grams):
    res = np.empty((len(bi_grams), len(bi_grams[0])), dtype=object)
    res[...] = bi_grams
    return res

def f_hpaulj(bi_grams):
    res = np.empty((len(bi_grams), len(bi_grams[0])), dtype=object)
    for i, j in np.ndindex(res.shape):
        res[i, j] = bi_grams[i][j]
    return res

print(np.all(f_pp_1(bi_grams) == f_pp_2(bi_grams)))
print(np.all(f_pp_1(bi_grams) == f_hpaulj(bi_grams)))

from timeit import timeit
kwds = dict(globals=globals(), number=1000)

print(timeit('f_pp_1(bi_grams)', **kwds))
print(timeit('f_pp_2(bi_grams)', **kwds))
print(timeit('f_hpaulj(bi_grams)', **kwds))

big = 10000 * bi_grams

print(timeit('f_pp_1(big)', **kwds))
print(timeit('f_pp_2(big)', **kwds))
print(timeit('f_hpaulj(big)', **kwds))

樣本輸出:

True                      <- same result for
True                      <- different methods
0.004281356999854324      <- frompyfunc          small input
0.002839841999957571      <- prealloc ellipsis   small input
0.02361366100012674       <- prealloc loop       small input
2.153144505               <- frompyfunc          large input
5.152567720999741         <- prealloc ellipsis   large input
33.13142323599959         <- prealloc looop      large input

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM