同时迭代/列表理解问题(在 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 中的合并报告)的主要内容,如果未能解决你的问题,请参考以下文章