pandas 如何在数据框中使用通配符执行VLOOKUP

f45qwnt8  于 2023-05-21  发布在  其他
关注(0)|答案(3)|浏览(103)

所以这里是我的reference dataframe,这是整理目标dataframe的dataframe:

A   B   C
0   1   1   1
1   3   *   y
2   x   *   *
3   x   4   7
4   1   7   9
5   *   1   z
6   y   1   0
7   3   1   6

这是目标数据框

A   B   C 
0   3   2   y
1   x   5   6
2   2   7   8
4   y   1   0

这是我的预期结果

A   B   C    Result
0   3   2   y     match
1   x   5   6     match
2   2   7   8   no match
4   y   1   0     match

我尝试了一种方法,它是concatenationg字符串,但它需要大量的组合列来过滤掉通配符,如下所示:

A   B   C   Concat1  Concat2   Concat3
0   1   1   1     1_1      1_1      1_1_1
1   3   *   y     3_        _y      3__y
2   x   *   *          ...
3   x   4   7          ...
4   1   7   9          ...
5   *   1   z          ...
6   y   1   0          ...
7   3   1   6          ...
bmp9r5qi

bmp9r5qi1#

也许你可以使用一个循环来检查匹配:

import pandas as pd
import numpy as np

def wildcard_vlookup(df_ref, df_target):
    def is_match(row):
        for _, ref_row in df_ref.iterrows():
            if all([(r=='*' or r==v) for r, v in zip(ref_row, row)]):
                return True
        return False
    df_target['Result'] = df_target.apply(is_match, axis=1)
    df_target['Result'] = np.where(df_target['Result'], 'match', 'no match')
    return df_target

data_ref = {
    'A': [1, 3, 'x', 'x', 1, '*', 'y', 3],
    'B': [1, '*', '*', 4, 7, 1, 1, 1],
    'C': [1, 'y', '*', 7, 9, 'z', 0, 6]
}
df_ref = pd.DataFrame(data_ref)
data_target = {
    'A': [3, 'x', 2, 'y'],
    'B': [2, 5, 7, 1],
    'C': ['y', 6, 8, 0]
}
df_target = pd.DataFrame(data_target)
df_result = wildcard_vlookup(df_ref, df_target)
print(df_result)

输出:

A  B  C    Result
0  3  2  y     match
1  x  5  6     match
2  2  7  8  no match
3  y  1  0     match
jtoj6r0c

jtoj6r0c2#

这里,您的问题是比较O(len(df_ref) * len(df_target))组合。该问题具有很高的时间复杂度。
它也不是微不足道的,特别是因为向量化很难,因为你的dtypesobject s(即您在同一列/行中混合了数字和字符串)。
你有两个选择:你要么耗尽你的时间资源(即让你的代码运行很长一段时间),要么耗尽你的空间资源(即让你的代码运行很长一段时间)。尝试并行化操作,但代价是分配大量内存)
如果你有无限的内存,我们可以做一个np.equal.outer

c = np.equal.outer(df_target.values, df_ref.values)[:, np.arange(len(df_target.columns)),
                                                    :, np.arange(len(df_ref.columns))].T

现在,我们比较所需的尺寸,并利用广播

(c | (df_ref.values == '*')[:, None, :]).all(2).any(0)

从而产生

array([ True,  True, False,  True])

一种可能的加速方法是用np.nan替换*,并尝试去掉xy,使所有dtypes都是数字(例如,dtypes)。使x成为9999或某个其它因子)。然后,我们可以执行上面的np.isnan(df_ref.values),而不是df_ref.values == '*'。这将使它更快,但内存分配仍然是要耗尽的资源。

i7uaboj4

i7uaboj43#

另一种可能的解决方案,其基于先前转换第一个 Dataframe 的行,然后使用正则表达式来获得匹配的想法:

from itertools import product
import re

aux2 = df2.astype(str).sum(axis=1)
df2['match'] = aux2
aux1 = df1.sum(axis=1).str.replace(r'\*', r'.?', regex=True)

matches = [[x, 'match'] for x, y in product(aux2, aux1) if (re.search(y, x))]

(df2.merge(pd.DataFrame.from_records(
    matches, columns=['match', 'Result']), 
           on='match', how='left')
 .drop('match', axis=1).fillna('no match'))

输出:

A  B  C    Result
0  3  2  y     match
1  x  5  6     match
2  2  7  8  no match
3  y  1  0     match

相关问题