定義
因式分解:將每個唯一對象映射到唯一的整數。通常情況下,映射到的整數範圍是從零到n - 1,其中n是唯一對象的數量。兩種變化也是典型的。類型1是編號以唯一對象被識別的順序出現的地方。類型2是首先排序唯一對象的地方,然後應用與類型1中相同的過程。如何分解元組列表?
的設置
考慮的元組tups
tups = [(1, 2), ('a', 'b'), (3, 4), ('c', 5), (6, 'd'), ('a', 'b'), (3, 4)]
我想這因式分解的列表爲
[0, 1, 2, 3, 4, 1, 2]
我知道有很多方法可以做到這一點。但是,我想盡可能有效地做到這一點。
我已經試過
pandas.factorize
並得到一個錯誤......
pd.factorize(tups)[0]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-84-c84947ac948c> in <module>()
----> 1 pd.factorize(tups)[0]
//anaconda/envs/3.6/lib/python3.6/site-packages/pandas/core/algorithms.py in factorize(values, sort, order, na_sentinel, size_hint)
553 uniques = vec_klass()
554 check_nulls = not is_integer_dtype(original)
--> 555 labels = table.get_labels(values, uniques, 0, na_sentinel, check_nulls)
556
557 labels = _ensure_platform_int(labels)
pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_labels (pandas/_libs/hashtable.c:21804)()
ValueError: Buffer has wrong number of dimensions (expected 1, got 2)
或者numpy.unique
,並得到不正確的結果......
np.unique(tups, return_inverse=1)[1]
array([0, 1, 6, 7, 2, 3, 8, 4, 5, 9, 6, 7, 2, 3])
我可以使用其中任一對元組
pd.factorize([hash(t) for t in tups])[0]
array([0, 1, 2, 3, 4, 1, 2])
耶的哈希值!這就是我想要的......那麼問題是什麼?
第一個問題
看看性能下降,由該技術
lst = [10, 7, 4, 33, 1005, 7, 4]
%timeit pd.factorize(lst * 1000)[0]
1000 loops, best of 3: 506 µs per loop
%timeit pd.factorize([hash(i) for i in lst * 1000])[0]
1000 loops, best of 3: 937 µs per loop
第二問題
散列不能保證唯一!
問題
什麼是因式分解元組的列表超快速的?
時序
兩個軸是在日誌空間
code
from itertools import count
def champ(tups):
d = {}
c = count()
return np.array(
[d[tup] if tup in d else d.setdefault(tup, next(c)) for tup in tups]
)
def root(tups):
return pd.Series(tups).factorize()[0]
def iobe(tups):
return np.unique(tups, return_inverse=True, axis=0)[1]
def get_row_view(a):
void_dt = np.dtype((np.void, a.dtype.itemsize * np.prod(a.shape[1:])))
a = np.ascontiguousarray(a)
return a.reshape(a.shape[0], -1).view(void_dt).ravel()
def diva(tups):
return np.unique(get_row_view(np.array(tups)), return_inverse=1)[1]
def gdib(tups):
return pd.factorize([str(t) for t in tups])[0]
from string import ascii_letters
def tups_creator_1(size, len_of_str=3, num_ints_to_choose_from=1000, seed=None):
c = len_of_str
n = num_ints_to_choose_from
np.random.seed(seed)
d = pd.DataFrame(np.random.choice(list(ascii_letters), (size, c))).sum(1).tolist()
i = np.random.randint(n, size=size)
return list(zip(d, i))
results = pd.DataFrame(
index=pd.Index([100, 1000, 5000, 10000, 20000, 30000, 40000, 50000], name='Size'),
columns=pd.Index('champ root iobe diva gdib'.split(), name='Method')
)
for i in results.index:
tups = tups_creator_1(i, max(1, int(np.log10(i))), max(10, i // 10))
for j in results.columns:
stmt = '{}(tups)'.format(j)
setup = 'from __main__ import {}, tups'.format(j)
results.set_value(i, j, timeit(stmt, setup, number=100)/100)
results.plot(title='Avg Seconds', logx=True, logy=True)
你需要維持這樣的順序嗎?''[0,3,1,4,2,3,1]'也可以嗎? – Divakar
@Divakar目前我不在乎。你可以選擇哪一個更方便。 – piRSquared
我認爲我們需要一個更好的基準測試,它既有字符串也有數字,當然應該足夠大,重複的次數應與示例中的重複次數一致。 – Divakar