2017-10-08 138 views
0

我得到了九个不同的数据帧,我想要将它们合并(或合并或更新)为单个数据帧。这些原始数据帧中的每一个都只包含两列,以秒为单位,并为该观测值。数据是这样的:熊猫:连接数据帧并合并相同列的值

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 

的问题是,前四个dataframes具有相同值列的名称,而其他值不是。因此,结果有三列带有前缀“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

调用在一个循环pd.merge导致quadratic copying和性能下降时DataFrames的长度或绝对数量较大。所以尽可能避免这种情况。

在这里,我们似乎要垂直串联的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的列表,并且可以一次将它们连接在一起,而无需迭代地创建中间DataFrame,因此避免了二次拷贝问题。

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

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


还有另一种方式来解决问题,并在某种程度上,它是漂亮,但它在循环中调用pd.merge,因此它可以从性能低下上述理由解释受苦。

但是,这个想法是这样的:默认情况下,pd.merge(left, right)合并在leftright共有的所有列标签上。所以,如果你省略on='Offset'(或'上=“时间”?),并使用

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

很不错的解决方案。同时我也想出了连接第一帧的解决方案。但我真的很喜欢你的减少电话。也会检查出来! – Matthias