【问题标题】:Pandas: join dataframes and merge values of identical columnsPandas:加入数据框并合并相同列的值
【发布时间】:2017-10-08 15:38:24
【问题描述】:

我有九个不同的数据帧,我想将它们加入(或合并或更新)到一个数据帧中。这些原始数据帧中的每一个仅包含两列,以秒为单位和该观察值。数据如下所示:

   Filter_type         Time
0          0.0  6333.137168


   Filter_type         Time
0          0.0  6347.422576


   Filter_type         Time
0          0.0  7002.406185


   Filter_type         Time
0          0.0  7015.845717


   Sign_pos_X         Time
0        11.5  6333.137168
1        25.0  6347.422576
2        25.5  7002.406185
3        38.0  7015.845717


   Sign_pos_Y         Time
0        -3.0  6333.137168
1         8.0  6347.422576
2        -7.5  7002.406185
3        -0.5  7015.845717


   Sign_pos_Z         Time
0         1.0  6333.137168
1         1.0  6347.422576
2         1.0  7002.406185
3         7.5  7015.845717


   Supplementary_sign_type         Time
0                      0.0  6333.137168
1                      0.0  6347.422576
2                      0.0  7002.406185
3                      0.0  7015.845717


          Time  vision_only_sign_type
0  6333.137168                    7.0
1  6347.422576                    9.0
2  7002.406185                    9.0
3  7015.845717                   35.0

由于我想将它们全部加入一个数据框,我尝试了以下方法:

df2 = None

for cell in df['Frames']:
    if not isinstance(cell, list):
        continue

    df_ = pd.DataFrame(cell)
    if df2 is None:
        # first iteration
        df2 = df_
        continue

    df2 = df2.merge(df_, on='Offset', how='outer') 
    #df2 = df2.join(df_)
    #df2.update(df_, join='outer')

df2

问题是,前四个数据框具有相同的值列名称,而其他数据框则没有。因此,结果包含三个前缀为“Filter_type”的列:

+----+-----------------+----------+-----------------+-----------------+-----------------+--------------+--------------+--------------+---------------------------+-------------------------+
|    |   Filter_type_x |   Offset |   Filter_type_y |   Filter_type_x |   Filter_type_y |   Sign_pos_X |   Sign_pos_Y |   Sign_pos_Z |   Supplementary_sign_type |   vision_only_sign_type |
|----+-----------------+----------+-----------------+-----------------+-----------------+--------------+--------------+--------------+---------------------------+-------------------------|
|  0 |               0 |  6333.14 |             nan |             nan |             nan |         11.5 |         -3   |          1   |                         0 |                       7 |
|  1 |             nan |  6347.42 |               0 |             nan |             nan |         25   |          8   |          1   |                         0 |                       9 |
|  2 |             nan |  7002.41 |             nan |               0 |             nan |         25.5 |         -7.5 |          1   |                         0 |                       9 |
|  3 |             nan |  7015.85 |             nan |             nan |               0 |         38   |         -0.5 |          7.5 |                         0 |                      35 |
+----+-----------------+----------+-----------------+-----------------+-----------------+--------------+--------------+--------------+---------------------------+-------------------------+

我的问题是:如何强制合并/加入将所有“Filter_type”列合并为一个。您可以看到每一行在所有此类列中只有一个值,而其他列是 NaN。 结果应如下所示(只有一个合并列“Filter_type”):

+----+----------+--------------+--------------+--------------+---------------------------+-------------------------+---------------+
|    |   Offset |   Sign_pos_X |   Sign_pos_Y |   Sign_pos_Z |   Supplementary_sign_type |   vision_only_sign_type |   Filter_type |
|----+----------+--------------+--------------+--------------+---------------------------+-------------------------+---------------|
|  0 |  6333.14 |         11.5 |         -3   |          1   |                         0 |                       7 |             0 |
|  1 |  6347.42 |         25   |          8   |          1   |                         0 |                       9 |             0 |
|  2 |  7002.41 |         25.5 |         -7.5 |          1   |                         0 |                       9 |             0 |
|  3 |  7015.85 |         38   |         -0.5 |          7.5 |                         0 |                      35 |             0 |
+----+----------+--------------+--------------+--------------+---------------------------+-------------------------+---------------+

【问题讨论】:

    标签: python join dataframe merge


    【解决方案1】:

    在循环中调用pd.merge 会导致quadratic copying 并在DataFrame 的长度或绝对数量很大时降低性能。所以尽可能避免这种情况。

    在这里,当DataFrames 有TimeFilter_type 列时,我们似乎希望垂直连接它们,而当DataFrames 缺少Filter_type 列时,我们希望水平连接它们:

    frames = [df.set_index('Time') for df in frames]
    filter_type_frames = pd.concat(frames[:4], axis=0)
    result = pd.concat([filter_type_frames] + frames[4:], axis=1)
    result = result.reset_index('Time')
    print(result)
    

    调用pd.concataxis=0 垂直连接,与axis=1 水平连接。 由于pd.concat 接受一个DataFrames 列表并且可以一次将它们全部连接起来而无需迭代地创建中间DataFrames,pd.concat 避免了二次复制问题。

    由于pd.concat 对齐索引,通过将索引设置为Time,数据将根据Time 正确对齐。

    请参阅下面的可运行示例。


    还有另一种解决问题的方法,在某种程度上它更漂亮,但它在循环中调用pd.merge,因此由于上述原因,它可能会遭受性能不佳的影响。

    然而,这个想法是这样的:默认情况下,pd.merge(left, right) 合并所有leftright 共有的列标签。因此,如果您省略 on='Offset'(或 `on='Time'?)并使用

    df2 = df2.merge(df_, how='outer') 
    

    然后合并将加入Offset(或Time)和Filter_type(如果两者都存在)。


    您可以通过使用进一步简化循环

    import functools
    df2 = functools.reduce(functools.partial(pd.merge, how='outer'), df['Frames'])
    

    循环隐藏在functools.reduce 中,但本质上,pd.merge 仍然在循环中被调用。所以虽然这很漂亮,但它可能性能不佳。


    import functools
    import pandas as pd
    frames = [pd.DataFrame({'Filter_type': [0.0], 'Time': [6333.137168]}),
              pd.DataFrame({'Filter_type': [0.0], 'Time': [6347.422576]}),
              pd.DataFrame({'Filter_type': [0.0], 'Time': [7002.406185]}),
              pd.DataFrame({'Filter_type': [0.0], 'Time': [7015.845717]}),
              pd.DataFrame({'Sign_pos_X': [11.5, 25.0, 25.5, 38.0],
                            'Time': [6333.137168, 6347.422576, 7002.406185, 7015.845717]}),
              pd.DataFrame({'Sign_pos_Y': [-3.0, 8.0, -7.5, -0.5],
                            'Time': [6333.137168, 6347.422576, 7002.406185, 7015.845717]}),
              pd.DataFrame({'Sign_pos_Z': [1.0, 1.0, 1.0, 7.5],
                            'Time': [6333.137168, 6347.422576, 7002.406185, 7015.845717]}),
              pd.DataFrame({'Supplementary_sign_type': [0.0, 0.0, 0.0, 0.0],
                            'Time': [6333.137168, 6347.422576, 7002.406185, 7015.845717]}),
              pd.DataFrame({'Time': [6333.137168, 6347.422576, 7002.406185, 7015.845717],
                            'vision_only_sign_type': [7.0, 9.0, 9.0, 35.0]})]
    
    result = functools.reduce(functools.partial(pd.merge, how='outer'), frames)
    print(result)
    
    frames = [df.set_index('Time') for df in frames]
    A = pd.concat(frames[:4], axis=0)
    result = pd.concat([A] + frames[4:], axis=1)
    result = result.reset_index('Time')
    print(result)
    # same result
    

    打印

       Filter_type         Time  Sign_pos_X  Sign_pos_Y  Sign_pos_Z  \
    0          0.0  6333.137168        11.5        -3.0         1.0   
    1          0.0  6347.422576        25.0         8.0         1.0   
    2          0.0  7002.406185        25.5        -7.5         1.0   
    3          0.0  7015.845717        38.0        -0.5         7.5   
    
       Supplementary_sign_type  vision_only_sign_type  
    0                      0.0                    7.0  
    1                      0.0                    9.0  
    2                      0.0                    9.0  
    3                      0.0                   35.0  
    

    【讨论】:

    • 非常好的解决方案。同时我也想出了连接第一帧的解决方案。但我真的很喜欢你的减少电话。也会检查一下!
    猜你喜欢
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 2019-07-31
    • 2021-02-18
    • 2023-04-01
    • 2021-09-10
    • 2021-12-17
    相关资源
    最近更新 更多