我必须合并两个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合并,然后删除重复项。即我会在这里
(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:根据df2
中的真/假值将split_groups
中的列组追加到数组group_mask
中
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
中所有值都不为False的列创建dfs数组
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)
第5步:遍历数组,并根据现有列合并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
中配置conf dfs
merged_df = pd.concat(merged_dfs, sort=False)
第7步:删除重复项
merged_df = merged_df.drop_duplicates()
第8步正在调用merged_df.columns.tolist()
,并且仅保留对最终结果有用的列。
我认为这种方法不是最佳方法-如果有人对如何提高效率有任何想法,我将非常感谢。感谢@qingshan关于循环的建议,它为我提供了最终循环遍历不同dfs列表的提示。
答案 0 :(得分:0)
您可以合并过滤的数据框以获取所需的内容。 使用它来过滤您的数据框,然后进行左合并以获取输出。
out_df = df1[~df1.isnull().T.any().T].merge(df2[~df2.isnull().T.any().T], on=['hotel_region', 'hotel_country', 'chain_name', 'brand_name'], how='left')
答案 1 :(得分:0)
尝试Combined_first函数
>>> df1 = pd.DataFrame([[1, np.nan]])
>>> df2 = pd.DataFrame([[3, 4]])
>>> df1.combine_first(df2)
0 1
0 1 4.0
答案 2 :(得分:0)
我猜您想合并具有相同列值的两行(忽略NaN)。如果数据不大,可以使用两个for循环来完成。
答案 3 :(得分:-1)
没有足够的声誉来发表评论,但是为什么不使用
df.dropna()
然后尝试合并数据框?