我想将九个不同的数据帧加入(或合并或更新)到一个数据帧中。这些原始数据帧中的每一个仅包含两列,以秒为单位和该观察值。数据如下所示:
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 |
+----+----------+--------------+--------------+--------------+---------------------------+-------------------------+---------------+
答案 0 :(得分:1)
在数据框架的长度或绝对数量很大时,在循环中调用pd.merge
会导致this thread并且性能会降低。所以尽可能避免这种情况。
在这里,似乎我们想要在Time
和Filter_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)
合并left
和right
共有的所有列标签。那么如果你省略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