【问题标题】:How to merge or combine 1 pandas dataframe to another one based on multiple conditions如何根据多个条件将 1 个 pandas 数据帧合并或组合到另一个数据帧
【发布时间】:2021-10-18 16:40:27
【问题描述】:

我有 2 个数据框:

df1 和 df2 ,df1 用来作为 df2 的参考或查找文件。这意味着我们需要使用 df1 的每一行来匹配 df2 的每一行,然后将 df1 合并到 df2 中,然后输出新的 df2。

df1:

    RB  BeginDate   EndDate    Valindex0
0   00  19000100    19811231    45
1   00  19820100    19841299    47
2   00  19850100    20010699    50
3   00  20010700    99999999    39

df2:

    RB  IssueDate   gs
0   L3  19990201    8
1   00  19820101    G
2   48  19820101    G
3   50  19820101    G
4   50  19820101    G
5   00  19860101    G
6   52  19820101    G
7   53  19820101    G
8   00  19500201    G

如何根据条件合并这两个数据框:

if df1['BeginDate'] <= df2['IssueDate'] <= df1['EndDate'] and df1['RB']==df2['RB']:
    merge the value of df1['Valindex0'] to df2

注意最后的输出是将df1合并到df2,因为df1就像是df2的参考或查找文件。这意味着我们需要使用df1的每一行来匹配df2的每一行,然后输出新的df2

输出应如下所示:

df2:

    RB  IssueDate   gs  Valindex0
0   L3  19990201    8   None
1   00  19820101    G   47    # df2['RB']==df1['RB'] and df2['IssueDate'] between df1['BeginDate'] and df1['EndDate'] of this row
2   48  19820101    G   None
3   50  19820101    G   None
4   50  19820101    G   None
5   00  19860101    G   50
6   52  19820101    G   None
7   53  19820101    G   None
8   00  19500201    G   45

我知道一种方法可以做到这一点,但它非常慢,尤其是当 d1 的长度很大时:

conditions = []

for index, row in df1.iterrows():
    conditions.append((df2['IssueDate']>= df1['BeginDate']) &
                      (df2['IssueDate']<= df1['BeginDate'])&
                      (df2['RB']==df1['RB']))

df2['Valindex0'] = np.select(conditions, df1['Valindex0'], default=None)

有更快的解决方案吗?

【问题讨论】:

    标签: python pandas dataframe numpy numpy-ndarray


    【解决方案1】:

    使用IntervalIndex -

    idx = pd.IntervalIndex.from_arrays(df1['BeginDate'],df1['EndDate'],closed='both')
    for x in df1['RB'].unique():
        mask = df2['RB']==x
        df2.loc[mask, 'Valindex0'] = df1.loc[idx.get_indexer(df2.loc[mask, 'IssueDate']), 'Valindex0'].values
    

    输出

       RB  IssueDate gs  Valindex0
    0  L3   19990201  8        NaN
    1  00   19820101  G       47.0
    2  48   19820101  G        NaN
    3  50   19820101  G        NaN
    4  50   19820101  G        NaN
    5  00   19860101  G       50.0
    6  52   19820101  G        NaN
    7  53   19820101  G        NaN
    8  00   19500201  G       45.0
    

    【讨论】:

    • 感谢您的回复,请问如果我有更多列需要检查,例如名为“type”的列,在两个数据框中,就像列 RB ,df1['type' ]=df2['type'],我可以在 df1[['RB','type']].unique():...中使用 x 吗?
    【解决方案2】:

    如果您不关心记录或索引的顺序,您可以这样做

    df1 = pd.read_clipboard()
    df2 = pd.read_clipboard()
    
    # pandas wants to cast this column as int
    df1['RB'] = '00'
    
    new_df = df2.merge(df1, how='outer', on='RB')
    
    mask = ((new_df['BeginDate'] <= new_df['IssueDate']) & (new_df['IssueDate'] <= new_df['EndDate'])
           )| new_df['Valindex0'].isnull()
    
    new_df[['RB','IssueDate', 'gs', 'Valindex0']][mask]
    

    这个想法是先做一个全外连接,然后过滤数据集。

    结果:

        RB  IssueDate   gs  Valindex0
    0   L3  19990201    8   NaN
    2   00  19820101    G   47.0
    7   00  19860101    G   50.0
    9   00  19500201    G   45.0
    13  48  19820101    G   NaN
    14  50  19820101    G   NaN
    15  50  19820101    G   NaN
    16  52  19820101    G   NaN
    17  53  19820101    G   NaN
    

    【讨论】:

    • 谢谢你的回复,我有一个问题,我可以不定义df1['RB'] = '00',因为RB是一个动态值,我不能定义,它不是始终等于 00,也可以等于 48 或 52 或任何其他数字
    • 嗨@William,您不需要定义df1['RB'] = '00'。当我复制您的数据集时,pandas 将该列转换为 int ,从而将所有值从 '00' 更改为 '0' 。那只是为了复制你的数据集
    猜你喜欢
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-19
    相关资源
    最近更新 更多