【发布时间】:2019-06-02 17:19:35
【问题描述】:
我必须合并两个 df。一个是我的主df,另一个有很多NaN
df1 样本:
code hotel_region hotel_country chain_name brand_name
9737 EUROPE ESTONIA Bridgestreet NaN
5397 LATIN AMERICA COSTA RICA Independent No Brand
2392 LATIN AMERICA ARUBA DIVI RESORTS NaN
9776 LATIN AMERICA BRAZIL Independent W Hotels
4720 LATIN AMERICA ARGENTINA Independent No Brand
df2 示例:
r_id hotel_region hotel_country chain_name brand_name
78 LATIN AMERICA HONDURAS Barcelo Hotels and Resorts NaN
92 LATIN AMERICA SANDWICH ISL Barcelo Hotels and Resorts NaN
151 NaN NaN Bridgestreet NaN
117 NORTH AMERICA CANADA Magnuson Hotels NaN
47 LATIN AMERICA BRAZIL NaN W Hotels
我想要的结果大致是这样的:
code hotel_region hotel_country chain_name brand_name r_id
9737 EUROPE ESTONIA Bridgestreet NaN 151
9776 LATIN AMERICA BRAZIL Independent W Hotels 47
合并应该只是“忽略” NaN 值,并且只在列值不是 NaN 的情况下合并。我尝试了不同的方法,但是 df2 中的数据有数十种可能出现 NaN 值。 df1 有 168k 行,df2 大约有 170 行,r_id 应该与任何匹配所有非 NaN 值的code 相关联。有没有人知道如何有效地做到这一点?
在对不同方法进行广泛研究后,似乎不存在忽略 NaN 的“神奇”方法。我考虑过在 df2 上应用掩码并分组,循环遍历它们,将每个组与 df1 合并,然后删除重复项。 IE。我会在这里
(True, True, True, True, False),
(True, False, False, True, False),
(True, True, True, False, True)
但是我不确定这是否是最好的方法,坦率地说,我对如何实施它感到困惑。
编辑 - 我最终是如何解决这个问题的
我最终探索了上述方法 - 在 df2 上应用蒙版,根据蒙版拆分它,将其与 df1 合并。
第 1 步:创建掩码
masked = df2[['hotel_region', 'hotel_country', 'chain_name', 'brand_name']]
mask = pd.notnull(masked)
第 2 步:根据 NaN (= False) 值对 df 进行分组
group_mask = mask.groupby(['hotel_region','hotel_country', 'chain_name','brand_name']).count().reset_index()
第 3 步:根据 group_mask 中的真/假值将 df2 中的列组附加到数组 split_groups 中
split_groups = []
for index, row in group_mask.iterrows():
bool_groups = []
# If the whole group is False, then cannot be taken in consideration,
# as it would result in a merge on the whole df1
if not any(row.to_dict().values()):
pass
else:
bool_groups.append(
[key for key in row.to_dict().keys() if row.to_dict()[key] == False])
bool_groups.append(
[key for key in row.to_dict().keys() if row.to_dict()[key] == True])
split_groups.append(bool_groups)
第 4 步:根据 df2 中的列创建 dfs 拆分数组,其中所有值都不为 False
mps = []
"""
First, we extract rows where i[0] is null. In the resulting df, we extract rows
where i[1] is not null. Then, we drop all columns with na values. In this way
we retain only columns good for the merge.
"""
for i in split_groups:
df = df2[(df2[i[0]].isnull()).all(1)]
df = df[(df[i[1]].notnull()).all(1)]
df = df.dropna(axis='columns', how='all')
mps.append(df)
第五步:遍历数组,根据已有的列合并2个dfs
merged_dfs = []
for i in range(len(mps)):
merged_dfs.append(df1.merge(mps[i], on=(split_groups[i][1]), how='left'))
第 6 步:在merged_dfs 中连接 dfs
merged_df = pd.concat(merged_dfs, sort=False)
第 7 步:删除重复项
merged_df = merged_df.drop_duplicates()
第 8 步调用 merged_df.columns.tolist() 并仅保留对最终结果有用的列。
我认为这种方法不是最佳的 - 如果有人对如何提高效率有任何想法,我将不胜感激。感谢 @qingshan 关于循环的建议,它给了我最终循环遍历不同 dfs 列表的提示。
【问题讨论】:
-
必须要有
r_id吗? -
不幸的是,这是我必须在 df1 中标记与 df2 相关的行的参数 :-)