同时迭代/列表理解问题(在 UDF 中获取 Pandas 中的合并报告)

Posted

技术标签:

【中文标题】同时迭代/列表理解问题(在 UDF 中获取 Pandas 中的合并报告)【英文标题】:Iterating simultaneously/List comprehension issue (in UDF to obtain Merge Report in Pandas) 【发布时间】:2013-10-09 22:34:55 【问题描述】:

Stata 用户会知道,在合并数据时会生成一个 _merge 变量,该变量表示 _merge 为 1 表示 merge 对该观察成功,为 2 表示观察仅在主数据集中,或者由 3 表示观察仅在使用数据集中。我正在尝试通过编写自己的函数在熊猫中重新创建它。我有以下工作:

def MergeReport(DF1, DF2, keys, HOW = 'outer'):

    if len(keys) == 1:
        KeysDF1 = set(DF1[keys[0]])
        KeysDF2 = set(DF2[keys[0]])
        MasterError = list(KeysDF1.difference(KeysDF2))
        UsingError = list(KeysDF2.difference(KeysDF1))
        MG = pd.merge(DF1, DF2, on = keys, how = HOW)
        MG['_merge'] = None

        for row in MG.index:
            if MG[keys[0]][row] in MasterError:
                MG['_merge'][row] = "merge_2"
            elif MG[keys[0]][row] in UsingError:
                MG['_merge'][row] = "merge_3"
            else:
                MG['_merge'][row] = "merge_1"

        return MG       

    else:
        KeysDF1 = set(zip(DF1[keys[0]], DF1[keys[1]]))      
        KeysDF2 = set(zip(DF2[keys[0]], DF2[keys[1]]))          
        MasterError = list(KeysDF1.difference(KeysDF2)) 
        UsingError = list(KeysDF2.difference(KeysDF1))
        MG = pd.merge(DF1, DF2, on = keys, how = HOW)
        MG['_merge'] = None

        for row in MG.index:
            if tuple([MG[keys[0]][row], MG[keys[1]][row]]) in MasterError:
                MG['_merge'][row] = "merge_2"
            elif tuple([MG[keys[0]][row], MG[keys[1]][row]]) in UsingError:
                MG['_merge'][row] = "merge_3"
            else:
                MG['_merge'][row] = "merge_1"

        return MG   

参数是 DataFrame1、DataFrame2、“键”列表(即要合并的列)和一个可选参数 HOW,该参数传递给 pd.merge 参数 how = HOW。最终,参数将扩展到 pd.merge 函数中的所有参数。

我认为我的问题很明显:我不知道如何编写代码以使其可以接受任意长度的键列表。我的问题发生在这里:

KeysDF1 = set(zip(DF1[keys[0]], DF1[keys[1]]))      
KeysDF2 = set(zip(DF2[keys[0]], DF2[keys[1]]))

我无法弄清楚如何编写此代码,以便可以遍历任意长度的键列表。特别是我尝试了列表理解:

KeysDF1 =   set(zip(tuple([DF1[keys[x]] for x in range(len(keys))])))   

但这不起作用,因为“系列对象是可变的,它们不能被散列”。 我想我也会在代码中发现类似的问题:

if tuple([MG[keys[0]][row], MG[keys[1]][row]]) in MasterError:
    MG['_merge'][row] = "merge_2"

编辑:在另一位用户的建议下,我发布了实现相同目标的替代方法。我不建议将此作为问题本身的解决方案,而只是一种避免该问题的方法:

def MergeReport(DF1, DF2, how = 'inner', on = None, left_on = None, right_on = None, \    left_index = False, right_index = False, \sort = False, suffixes = ('_x', '_y'), copy = True):
    DF1['Master'] = 1
    DF2['Using'] = 2

    MDF = pd.merge(DF1, DF2, how = how, on = on, left_on = left_on, right_on = right_on, left_index = left_index, right_index = right_index, \
sort = sort, suffixes = suffixes, copy = copy)

    MDF['Master'].fillna(value = 0, inplace = True)
    MDF['Using'].fillna(value = 0, inplace = True)
    MDF['_Merge'] = MDF['Master'] + MDF['Using']
    del MDF['Master']
    del MDF['Using']
    List = ['1_MasterOnly', '2_UsingOnly', '3_Matched']
    LIST = [List[int(MDF['_Merge'][row] - 1)] for row in MDF.index]
    MDF['_Merge'] = np.array(LIST)
    return MDF

【问题讨论】:

一位同事刚刚指出,更简单的方法是在 DF1 中创建一个所有值都等于 1 的列,并在 DF2 中创建一个所有值都等于 2 的变量,并且然后在合并的数据框中创建一个等于这两个变量之和的 _merge 变量,这将表明问题出在哪里,即 1 仅在 master 中,2 在仅使用和 3 成功......我猜要容易得多,但是我仍然想知道上述解决方案可能是什么? 随时发布您的实用解决方案作为答案。 我该怎么做?回答我自己的问题? 我不确定我的问题是否有答案,我只有一个替代解决方案 它对其他人来说会比现在这里什么都没有。 【参考方案1】:

不确定我理解正确,但概括

KeysDF1 = set(zip(DF1[keys[0]], DF1[keys[1]]))

在我看来不是

KeysDF1 =   set(zip(tuple([DF1[keys[x]] for x in range(len(keys))])))

而是

KeysDF1 =   set(zip(*tuple([DF1[keys[x]] for x in range(len(keys))])))

或者干脆

KeysDF1 =   set(zip(*[DF1[keys[x]] for x in range(len(keys))]))

【讨论】:

以上是关于同时迭代/列表理解问题(在 UDF 中获取 Pandas 中的合并报告)的主要内容,如果未能解决你的问题,请参考以下文章

迭代器

Spark迭代算法UDF在每次迭代中被多次触发

列表理解中的双重迭代

带有 Pandas 矢量化 UDF 的 Spark 3

是否可以在 jstl 中使用 foreach 同时迭代两个项目?

列表理解列表中的元组列表