[英]How to subtract all elements in list from one element in another list?
[英]Keep all elements in one list from another
我有兩個大列表train
和keep
,后者包含獨特的元素,例如
train = [1, 2, 3, 4, 5, 5, 5, 5, 3, 2, 1]
keep = [1, 3, 4]
有沒有辦法創建一個新列表,其中包含keep
使用sets
的train
所有元素? 最終結果應該是:
train_keep = [1, 3, 4, 3, 1]
目前我正在使用itertools.filterfalse
from how to keep a list of elements based on another list但它很慢,因為列表很大......
將列表keep
轉換為set
,因為它將經常檢查。 迭代train
,因為您想保持順序並重復。 這使得set
不是一個選項。 即使是這樣,也無濟於事,因為無論如何迭代都必須發生:
keeps = set(keep)
train_keep = [k for k in train if k in keeps]
一個懶惰的,可能更慢的版本會像
train_keep = filter(lambda x: x in keeps, train)
這些選項都不會給你帶來很大的加速,你可能最好使用 numpy 或 pandas 或其他一些在 C 中實現循環並將數字存儲為比完整的 python 對象更簡單的庫。 這是一個示例 numpy 解決方案:
train = np.array([...])
keep = np.array([...])
train_keep = train[np.isin(train, keep)]
這可能是一個O(M * N)
算法而不是O(M)
集查找,但是如果檢查keep
N
元素比名義上的O(1)
查找快,那么你就贏了。
您可以使用排序查找獲得更接近O(M log(N))
東西:
train = np.array([...])
keep = np.array([...])
keep.sort()
ind = np.searchsorted(keep, train, side='left')
ind[ind == keep.size] -= 1
train_keep = train[keep[ind] == train]
更好的替代方法可能是將np.inf
或最大越界整數附加到已排序的keep
數組中,這樣您就不np.inf
缺失與extra
邊緣元素區分開來。 像np.max(train.max() + 1, keep.max())
這樣的東西會做:
train = np.array([...])
keep = np.array([... 99999])
keep.sort()
ind = np.searchsorted(keep, train, side='left')
train_keep = train[keep[ind] == train]
對於train.size = 10000
和keep.size = 10
隨機輸入,numpy 方法在我的筆記本電腦上快約 10 倍。
>>> keep_set = set(keep)
>>> [val for val in train if val in keep_set]
[1, 3, 4, 3, 1]
請注意,如果keep
很小,則將其轉換為set
可能沒有任何性能優勢(以確保為基准)。
這是一個選項:
train = [1, 2, 3, 4, 5, 5, 5, 5, 3, 2, 1]
keep = [1, 3, 4]
keep_set = set(keep)
res = [item for item in train if item in keep_set]
# [1, 3, 4, 3, 1]
我使用keep_set
來加快查找速度。
邏輯是相同的,但請嘗試一下,對於您的情況,生成器可能更快:
def keep_if_in(to_keep, ary):
for element in ary:
if element in to_keep:
yield element
train = [1, 2, 3, 4, 5, 5, 5, 5, 3, 2, 1]
keep = [1, 3, 4]
train_keep = keep_if_in(set(keep), train)
最后,在需要時轉換為列表或直接迭代生成器:
print(list(train_keep))
# alternatively, uncomment this and comment out the line above,
# it's because a generator can be consumed once
# for e in train_keep:
# print(e)
這是對 Mad Physicist 的巧妙技巧的略微擴展,以涵蓋列表包含字符且其中一個是數據框列的情況(我試圖在數據框中查找項目列表,包括所有重復項,但顯而易見的答案是, mylist.isin(df['col')
刪除了重復項)。 我調整了他的回答來處理 Numpy 可能截斷字符數據的問題。
#Sample dataframe with strings
d = {'train': ['ABC_S8#Q09#2#510a#6','ABC_S8#Q09#2#510l','ABC_S8#Q09#2#510a#6','ABC_S8#Q09#2#510d02','ABC_S8#Q09#2#510c#8y','ABC_S8#Q09#2#510a#6'], 'col2': [1,2,3,4,5,6]}
df = pd.DataFrame(data=d)
keep_list = ['ABC_S8#Q09#2#510a#6','ABC_S8#Q09#2#510b13','ABC_S8#Q09#2#510c#8y']
#Make sure the Numpy datatype accomodates longest string in either list
maxlen = max(len(max(keep_list, key = len)),len(max(df['train'], key = len)))
strtype = '<U'+ str(maxlen)
#Convert lists to Numpy arrays
keep = np.array(keep_list,dtype = strtype)
train = np.array(df['train'],dtype = strtype)
#Algorithm
keep.sort()
ind = np.searchsorted(keep, train, side='left')
ind[ind == keep.size] -= 1
train_keep = df[keep[ind] == df['train']] #reference the original dataframe
我發現這比我嘗試過的其他解決方案要快得多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.