![](/img/trans.png)
[英]python - Fastest way to find index of an element in list by comparing to elements of another list
[英]Fastest way to find index of elements in a list
我有一組具有某些功能(例如Y)的示例(例如X),我需要在上面運行一些機器學習算法(例如PCA)。 一種方法是生成矩陣(樣本,特征)。 我構建矩陣的方法涉及2個步驟:
例如:考慮以下示例
sample1 = A, B, D
sample2 = A, C, E
sample3 = A, C, D
生成矩陣
生成此矩陣的挑戰在於數據非常龐大。 行數為465337 ,列數為35526155 。
生成池大約花費了20分鍾,即使這很慢,我也很滿意。 但是,當生成矩陣的向量(即行)時,我必須考慮樣本中的所有值,以得到池中該值的索引。
這花費了大量時間。 有沒有更好的方法來查找元素索引? 如果程序本身不是最佳方法,請讓我知道生成矩陣的更好方法。
另外,我只是存儲索引並從中構造CSR矩陣,而不是密集矩陣。
您可以使用scikit-learn的Count Vectorizer實現這種類型的編碼。 請參閱此處的示例用例。 因為您提到了機器學習並且正在使用Python,所以我認為您通常對sklearn熟悉。
但是,由於CountVectorizer用於文本標記,因此將其用於您的問題有點麻煩。
例如,如果您使用以下格式輸入數據:
samples = [['A', 'B', 'D'],
['A', 'C', 'E'],
['A', 'C', 'D']]
您應該首先將內部列表轉換為字符串:
samples_s = ["".join(l) for l in samples]
這使
['ABD', 'ACE', 'ACD']
現在,您可以適合CountVectorizer的實例。 您只需要定義什么構成令牌。 在這里,我使用了一個簡單的正則表達式來定義任何單個字符(例如“ A”,“ B”或“ C”)作為標記。 您還可以提供靜態詞匯表。
vec = CountVectorizer(token_pattern='.')
X = vec.fit_transform(samples_s)
調用X.toarray()
返回
array([[1, 1, 0, 1, 0],
[1, 0, 1, 0, 1],
[1, 0, 1, 1, 0]], dtype=int64)
使用sklearn的實現應該比自己進行編碼要快得多。
正如我在評論中提到的那樣,您希望為此使用sklearn.feature_extraction.text.CountVectorizer
,並帶有binary=True
參數,因為您實際上並不希望計數。 您將創建編碼並輸出稀疏矩陣以啟動!
但是,如果您對方法的基本問題感興趣,從根本上講,問題是您使用的是序列類型 , list
,其中.index
方法是線性時間操作。 當您嘗試使用列表時,您會感到這一事實的痛苦。 以下是僅使用字典即可如何更有效地執行此操作的示意圖 :
In [15]: tokens = list('qwertydfgndjfkgnf')
In [16]: pool = {}
In [17]: for t in tokens:
...: pool.setdefault(t, len(pool))
...:
In [18]: pool
Out[18]:
{'d': 6,
'e': 2,
'f': 7,
'g': 8,
'j': 10,
'k': 11,
'n': 9,
'q': 0,
'r': 3,
't': 4,
'w': 1,
'y': 5}
In [19]: tokens.index('g') # ew, O(n) time complexity
Out[19]: 8
In [20]: pool['g'] # nice! O(1) time complexity
Out[20]: 8
現在,該池包含從標記到索引的編碼。 在這里訪問索引是一個固定時間的操作。 這將大大提高性能。 事實上,因為我們只是做一個dict
,首先,從一個不轉換set
到一個list
,這將通過大量的減少您的持續性因素。
請注意,以上內容實質上是sklearn
對象正在執行的操作。
https://github.com/scikit-learn/scikit-learn/blob/ab93d65/sklearn/feature_extraction/text.py#L745
但是請注意,它們使用defaultdict
,它通過以下令人愉悅的小方法針對此類情況進行了優化:
In [24]: from collections import defaultdict
In [25]: pool = defaultdict()
In [26]: pool.default_factory = pool.__len__
In [27]: for t in tokens:
...: pool[t]
...:
In [28]: pool
Out[28]:
defaultdict(<method-wrapper '__len__' of collections.defaultdict object at 0x1088aa9f8>,
{'d': 6,
'e': 2,
'f': 7,
'g': 8,
'j': 10,
'k': 11,
'n': 9,
'q': 0,
'r': 3,
't': 4,
'w': 1,
'y': 5})
當它們在文檔上循環時,它們還會構建稀疏表示,因此它們實際上僅對數據集進行一次傳遞。 因此,sklearn對象的優化程度與您將要獲得的優化程度一樣。 sklearn的源代碼實際上是很容易上手的,值得檢查一下它們僅使用不帶Cython擴展或任何內容的純python完成的工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.