2016-04-24 23 views
5

我有兩個等長的列表。第一個列表l1包含數據。映射兩個沒有循環的列表

l1 = [2, 3, 5, 7, 8, 10, ... , 23] 

第二個列表l2包含類別中l1數據屬於:

l2 = [1, 1, 2, 1, 3, 4, ... , 3] 

如何可以劃分基於由數字定義的位置,如在第二列表1, 2, 3, 4第一列表,使用列表理解lambda函數。例如,第一個列表中的2, 3, 7與第二個列表中的對應值屬於同一個分區。

分區的數量在開始時是已知的。

+1

你說的分區是什麼意思?預期的輸出數據結構是什麼?一個列表?字典? – timgeb

+0

@timgeb什麼都行。目標是在[此算法]上找到質心(http://stanford.edu/~cpiech/cs221/handouts/kmeans.html) –

回答

9

您可以使用字典:

>>> l1 = [2, 3, 5, 7, 8, 10, 23] 
>>> l2 = [1, 1, 2, 1, 3, 4, 3] 

>>> d = {} 
>>> for i, j in zip(l1, l2): 
...  d.setdefault(j, []).append(i) 
... 
>>> 
>>> d 
{1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]} 
+0

*「(...)沒有循環」*部分? – jDo

8

如果dict是好的,我建議使用defaultdict

>>> from collections import defaultdict 
>>> d = defaultdict(list) 
>>> for number, category in zip(l1, l2): 
...  d[category].append(number) 
... 
>>> d 
defaultdict(<type 'list'>, {1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]}) 

考慮使用itertools.izip內存效率,如果你正在使用Python 2

這與Kasramvd的基本相同的解決方案,但我認爲defaultdict使它有點簡單呃閱讀。

+0

可以針對性能進行優化嗎?我的數據集真的很大。 –

+1

@SantoshLinkha是的,對大列表使用'itertools.izip'。 – timgeb

2

這會給使用列表中理解的分區列表:

>>> l1 = [2, 3, 5, 7, 8, 10, 23] 
>>> l2 = [1, 1, 2, 1, 3, 4, 3] 
>>> [[value for i, value in enumerate(l1) if j == l2[i]] for j in set(l2)] 
[[2, 3, 7], [5], [8, 23], [10]] 
1

嵌套列表理解:

[ [ l1[j] for j in range(len(l1)) if l2[j] == i ] for i in range(1, max(l2)+1)]

1

如果是合理的,具有存儲在numpy數據ndarrays您可以使用擴展索引

{i:l1[l2==i] for i in set(l2)} 

來構建由類別代碼索引的ndarrays的字典。

有關聯的開銷l2==i(即建設爲每個類別一個新的布爾數組)與類別數量的增長,這樣你就可以與要檢查哪一種選擇,無論是numpydefaultdict,更快的數據。

我與n=200000nc=20numpy測試快於defaultdict + izip(124 VS 165毫秒),但具有nc=10000numpy爲(多)慢(11300 VS 251毫秒)

1

使用一些itertoolsoperator糖果和一種可以在一個班輪做到這一點:

>>> l1 = [2, 3, 5, 7, 8, 10, 23] 
>>> l2 = [1, 1, 2, 1, 3, 4, 3] 
>>> itertools.groupby(sorted(zip(l2, l1)), operator.itemgetter(0)) 

這樣做的結果是可以重複在itertools.groupby對象:

>>> for g, li in itertools.groupby(sorted(zip(l2, l1)), operator.itemgetter(0)): 
>>>  print(g, list(map(operator.itemgetter(1), li))) 

1 [2, 3, 7] 
2 [5] 
3 [8, 23] 
4 [10] 
+0

我用'n = 200000'和'nc = 20'測量了1960毫秒的最佳時間。因爲大部分時間都花在「排序」(只是一個合理的猜測)上,所以對於更大的'nc',你有更好的定時,例如'nc = 200' - > 1880 ms,'nc = 2000' - > 1820毫秒和'nc = 10000' - > 1680毫秒。我想知道當排序的數據有更多差異時,底層排序算法是否表現更好... – gboffi

1

這不是一個列表理解,而是一個字典理解。它類似於@ cromod的解決方案,但會保留l2的 「類別」:

{k:[val for i, val in enumerate(l1) if k == l2[i]] for k in set(l2)} 

輸出:

>>> l1 
[2, 3, 5, 7, 8, 10, 23] 
>>> l2 
[1, 1, 2, 1, 3, 4, 3] 
>>> {k:[val for i, val in enumerate(l1) if k == l2[i]] for k in set(l2)} 
{1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]} 
>>>