繁体   English   中英

在非空值上合并 2 个数据帧

[英]Merge 2 dataframes on notnull values

我必须合并两个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 步:根据split_groups中的 true/false 值将df2的列组附加到数组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中的列创建 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)

第 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 dfs 中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 列表的提示。

您可以合并过滤的数据框以获取所需的内容。 使用它来过滤您的数据框,然后进行左合并以获取输出。

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')

尝试Combined_first函数

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.combine_first.html#pandas.DataFrame.combine_first

>>> df1 = pd.DataFrame([[1, np.nan]])
>>> df2 = pd.DataFrame([[3, 4]])
>>> df1.combine_first(df2)

   0    1
0  1  4.0

我猜您想合并具有相同列值的两行(忽略NaN)。 如果数据不大,则可以使用两个for循环来完成。

没有足够的声誉来发表评论,但是为什么不使用

df.dropna()

然后尝试合并数据框?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM