Pandas:连接数据帧并合并相同列的值

时间:2017-10-08 15:38:25

标签: python join dataframe merge

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

   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 |
+----+----------+--------------+--------------+--------------+---------------------------+-------------------------+---------------+

1 个答案:

答案 0 :(得分:1)

在数据框架的长度或绝对数量很大时,在循环中调用pd.merge会导致this thread并且性能会降低。所以尽可能避免这种情况。

在这里,似乎我们想要在TimeFilter_type列时垂直连接DataFrame,并且我们希望在DataFrame缺少Filter_type列时水平连接:< / p>

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.concat axis=0垂直连接,水平axis=1。 由于pd.concat接受DataFrame的列表并且可以一次性连接它们而不迭代地创建中间DataFrame,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