我正在嘗試在我的大資料上使用 numpy 的廣播功能。我的串列列可以在許多行中包含數百個元素。我需要根據串列列中列值的存在來過濾行。如果 number incol_a存在于 中col_b,我需要對該行進行過濾。
樣本資料:
import pandas as pd
import numpy as np
dt = pd.DataFrame({'id' : ['a', 'a', 'a', 'b', 'b'],
'col_a': [[1],[2],[5],[1],[2]],
'col_b': [[2],[2,4],[2,5,7],[4],[3,2]],
})
dt
id col_a col_b
0 a [1] [2]
1 a [2] [2, 4]
2 a [5] [2, 5, 7]
3 b [1] [4]
4 b [2] [3, 2]
我嘗試了下面的代碼來添加維度col_b并檢查該值是否存在于col_a:
(dt['col_a'] == dt['col_b'][:,None]).any(axis = 1)
但我得到以下錯誤:
ValueError: ('Shapes must match', (5,), (5, 1))
有人可以讓我知道什么是正確的方法。
uj5u.com熱心網友回復:
import pandas as pd
import numpy as np
from itertools import product
根據逗號決議列:
dt2 = pd.DataFrame([j for i in dt.values for j in product(*i)], columns=dt.columns)
過濾到 col_a 等于 col_b 的地方:
dt2 = dt2[dt2['col_a'] == dt2['col_b']]
結果是:

uj5u.com熱心網友回復:
我想您已經被告知numpy“矢量化”是加速代碼的關鍵,但您并沒有很好地理解它是什么。您可以將其應用于任何pandas任務并不是什么神奇的事情。它只是充分利用numpy陣列方法的“速記”,也就是說,實際學習numpy.
但是,讓我們探討一下您的任務:
In [205]: dt = pd.DataFrame({'id' : ['a', 'a', 'a', 'b', 'b'],
...: 'col_a': [[1],[2],[5],[1],[2]],
...: 'col_b': [[2],[2,4],[2,5,7],[4],[3,2]],
...: })
In [206]: dt
Out[206]:
id col_a col_b
0 a [1] [2]
1 a [2] [2, 4]
2 a [5] [2, 5, 7]
3 b [1] [4]
4 b [2] [3, 2]
In [207]: dt.dtypes
Out[207]:
id object
col_a object
col_b object
dtype: object
因為列包含串列,所以它們dtype是物件;他們有對串列的參考。
在列上做事==,pandasSeries與用它們的值陣列做事是不一樣的。
但要關注 numpy 方面,讓我們獲取 numpy 陣列:
In [208]: a = dt['col_a'].to_numpy()
In [209]: b = dt['col_b'].to_numpy()
In [210]: a
Out[210]:
array([list([1]), list([2]), list([5]), list([1]), list([2])],
dtype=object)
In [211]: b
Out[211]:
array([list([2]), list([2, 4]), list([2, 5, 7]), list([4]), list([3, 2])],
dtype=object)
快速numpy操作使用編譯代碼,并且在大多數情況下,僅適用于數字資料型別。像這樣的陣列,包含對串列的參考,基本上與串列相同。數學和其他運算(如相等)以串列理解速度運行。這可能比 pandas 速度更快,但與高度吹噓的“矢量化”numpy 速度不同。
因此,讓我們對這些串列的元素進行串列理解。這很像 pandas apply,盡管我認為它更快(眾所周知,pandas apply 很慢)。
In [212]: [i in j for i,j in zip(a,b)]
Out[212]: [False, False, False, False, False]
糟糕,不匹配 - 一定是因為ifroma是一個串列。讓我們提取該數字:
In [213]: [i[0] in j for i,j in zip(a,b)]
Out[213]: [False, True, True, False, True]
讓 col_a 包含串列而不是數字對你沒有幫助。
由于a和b是陣列,我們可以使用==, 但本質上與 [212] 相同的操作(timeit 稍微好一點):
In [214]: a==b
Out[214]: array([False, False, False, False, False])
我們可以組成b一個 (5,1) 陣列,但為什么呢?
In [215]: b[:,None]
Out[215]:
array([[list([2])],
[list([2, 4])],
[list([2, 5, 7])],
[list([4])],
[list([3, 2])]], dtype=object)
我認為您試圖模仿這樣的陣列比較,針對 (3,1) 廣播 (5,) 以生成 (3,5) 真值表:
In [216]: x = np.arange(5); y = np.array([3,5,1])
In [217]: x==y[:,None]
Out[217]:
array([[False, False, False, True, False],
[False, False, False, False, False],
[False, True, False, False, False]])
In [218]: (x==y[:,None]).any(axis=1)
Out[218]: array([ True, False, True])
isin可以做同樣的比較:
In [219]: np.isin(x,y)
Out[219]: array([False, True, False, True, False])
In [220]: np.isin(y,x)
Out[220]: array([ True, False, True])
雖然這適用于數字,但不適用于串列陣列,尤其是您想要a針對b. 您沒有a針對所有b.
由于中的串列a大小相同,我們可以將它們連接成一個數字陣列:
In [225]: np.hstack(a)
Out[225]: array([1, 2, 5, 1, 2])
我們不能這樣做,b因為串列非常大。作為一般規則,當您有大小不同的串列(或陣列)時,您無法進行快速數字numpy數學和比較。
我們可以a針對 (5,1)測驗 (5,) b,生成 (5,5) 真值表:
In [227]: a==b[:,None]
Out[227]:
array([[False, True, False, False, True],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False]])
但那是True針對第一行的幾個單元格;這就是list([2])fromb與a.
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/533462.html
標籤:Python熊猫麻木的
