Gar*_*ler 4 python numpy dataframe pandas
这是我的问题的延续.比较两个pandas数据帧行的最快方法?
我有两个数据帧A和B:
A 是1000行×500列,填充二进制值表示是否存在.
对于一个简洁的例子:
A B C D E
0 0 0 0 1 0
1 1 1 1 1 0
2 1 0 0 1 1
3 0 1 1 1 0
Run Code Online (Sandbox Code Playgroud)
B 是1024行×10列,是二进制形式的0到1023的完整迭代.
例:
0 1 2
0 0 0 0
1 0 0 1
2 0 1 0
3 0 1 1
4 1 0 0
5 1 0 1
6 1 1 0
7 1 1 1
Run Code Online (Sandbox Code Playgroud)
我试图找到A特定10列的哪些行A与每行对应B.
每一行都A[My_Columns_List]保证在某个地方B,但并不是每一行都B与一行匹配A[My_Columns_List]
例如,我想显示列[B,D,E]的A,
行[1,3]的匹配了行[6]的B,
排[0]A的匹配了行[2]的B,
排[2]A的匹配了行[3]的B.
我尝试过使用:
pd.merge(B.reset_index(), A.reset_index(),
left_on = B.columns.tolist(),
right_on =A.columns[My_Columns_List].tolist(),
suffixes = ('_B','_A')))
Run Code Online (Sandbox Code Playgroud)
这有效,但我希望这种方法更快:
S = 2**np.arange(10)
A_ID = np.dot(A[My_Columns_List],S)
B_ID = np.dot(B,S)
out_row_idx = np.where(np.in1d(A_ID,B_ID))[0]
Run Code Online (Sandbox Code Playgroud)
但是当我这样做时,out_row_idx返回一个包含所有索引的数组A,这并没有告诉我什么.我认为这个方法会更快,但我不知道为什么它返回一个从0到999的数组.任何输入都将不胜感激!
此外,这些方法还归功于@jezrael和@Divakar.
我会坚持我最初的答案,但也许可以解释得更好.
您要比较2个pandas数据帧.因此,我将构建数据帧.我可能会使用numpy,但我的输入和输出将是数据帧.
你说我们有一个1000 x 500的1和0阵列.让我们构建它.
A_init = pd.DataFrame(np.random.binomial(1, .5, (1000, 500)))
A_init.columns = pd.MultiIndex.from_product([range(A_init.shape[1]/10), range(10)])
A = A_init
Run Code Online (Sandbox Code Playgroud)
另外,我给了A一个MultiIndex容易按10列的分组.
这与@Divakar的回答非常类似,我将指出一个小的差异.
对于一组10个1和0,我们可以将它视为长度为8的位数组.然后我们可以通过使用幂积为2的点积来计算它的整数值.
twos = 2 ** np.arange(10)
Run Code Online (Sandbox Code Playgroud)
我可以像这样一次为每组10个1和0执行此操作
AtB = A.stack(0).dot(twos).unstack()
Run Code Online (Sandbox Code Playgroud)
stack为了更优雅地制作点积,我将50行10列放入列中.然后我带着它回来了unstack.
我现在有一个1000 x 50的数字数据帧,范围从0到1023.
假设B是一个数据帧,每行包含1024个1和0的唯一组合之一.B应按如下排序B = B.sort_values().reset_index(drop=True).
这是我认为上次解释失败的部分.看着
AtB.loc[:2, :2]
Run Code Online (Sandbox Code Playgroud)
(0, 0)位置中的该值951意味着第一行中的第一组10个1和0 与索引A中的行匹配.那正是你想要的!!!有趣的是,我从未看过B.你知道为什么,B无关紧要!这只是一种表达从0到1023的数字的愚蠢方式.这与我的答案不同,我忽略了.忽略这个无用的步骤应该可以节省时间.B951B
这些都是需要两个dataframes的所有功能A,并B返回指数,其中的数据帧A匹配B.剧透警报,我会B完全忽略.
def FindAinB(A, B):
assert A.shape[1] % 10 == 0, 'Number of columns in A is not a multiple of 10'
rng = np.arange(A.shape[1])
A.columns = pd.MultiIndex.from_product([range(A.shape[1]/10), range(10)])
twos = 2 ** np.arange(10)
return A.stack(0).dot(twos).unstack()
Run Code Online (Sandbox Code Playgroud)
def FindAinB2(A, B):
assert A.shape[1] % 10 == 0, 'Number of columns in A is not a multiple of 10'
rng = np.arange(A.shape[1])
A.columns = pd.MultiIndex.from_product([range(A.shape[1]/10), range(10)])
# use clever bit shifting instead of dot product with powers
# questionable improvement
return (A.stack(0) << np.arange(10)).sum(1).unstack()
Run Code Online (Sandbox Code Playgroud)
我正在引导我的内心@Divakar(读,这是我从Divakar学到的东西)
def FindAinB3(A, B):
assert A.shape[1] % 10 == 0, 'Number of columns in A is not a multiple of 10'
a = A.values.reshape(-1, 10)
a = np.einsum('ij->i', a << np.arange(10))
return pd.DataFrame(a.reshape(A.shape[0], -1), A.index)
Run Code Online (Sandbox Code Playgroud)
f = lambda A: pd.DataFrame(np.einsum('ij->i', A.values.reshape(-1, 10) << np.arange(10)).reshape(A.shape[0], -1), A.index)
Run Code Online (Sandbox Code Playgroud)
像它一样使用它
f(A)
Run Code Online (Sandbox Code Playgroud)
FindAinB3速度提高了一个数量级
| 归档时间: |
|
| 查看次数: |
1310 次 |
| 最近记录: |