簡體   English   中英

查找列表中元素索引的最快方法

[英]Fastest way to find index of elements in a list

我有一組具有某些功能(例如Y)的示例(例如X),我需要在上面運行一些機器學習算法(例如PCA)。 一種方法是生成矩陣(樣本,特征)。 我構建矩陣的方法涉及2個步驟:

  1. 獲取整個數據集的所有特征值。 我們稱它為游泳池。
  2. 對於樣本,對於樣本中的每個值,在池中找到該值的索引。 值存在的索引為1,不存在的索引為0。

例如:考慮以下示例

sample1 = A, B, D
sample2 = A, C, E
sample3 = A, C, D
  1. 生成的池= A,B,C,D,E
  2. 生成矩陣

    • 樣本1 => 1,1,0,1,0
    • 樣本2 => 1,0,1,0,1
    • 樣本3 => 1,0,0,1,0

生成此矩陣的挑戰在於數據非常龐大。 行數為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.

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