熊猫:如何通过最接近的索引匹配来组合两个数据框?

时间:2019-03-26 20:08:50

标签: python pandas

我有两个数据帧df1, df2,它们的索引类型相同,但是几乎没有相同的匹配项。索引也可能有重复项。列A和B将由内部唯一值组成。所有索引和列都是有序的,但方向不同。 df1.index正在下降,df1['A']正在下降。 df2.index上升而df2['B']下降。

df1:(左侧数字是数据框的未命名索引)

            A
80 -13.545215
76 -12.270691
73 -11.274724
65  -8.280187
38  -7.965972
13  -7.788130
10  -6.690969
6   -5.273063

df2:

            B
8  -13.827641
10 -12.283885
14 -11.459951
62 -11.067622
64 -10.745988
87 -10.661594
95  -9.816053
97  -7.740810

我想组合数据帧,以便将df2['B']中的值放置到距df2中的df1最近的对应索引处,以便所需的输出采用以下形式:

            B         A
8  -13.827641 -6.690969
10 -12.283885 -6.690969
14 -11.459951 -7.965972
62 -11.067622 -8.280187
64 -10.745988 -8.280187
87 -10.661594  NaN
95  -9.816053  NaN
97  -7.740810  NaN

如果从绝对角度而言最接近的索引A低于索引B,则索引A的上限值是正确的匹配项。如果索引B在索引A中没有更高的对应匹配,则NaN是正确的匹配。

到目前为止,我已经使用pd.merge()fillna()进行了必要的分析。但是有些人可能发现对插值/综合数据进行分析是“不自然的”。无论如何,这就是我一直在做的事情:

pd.merge()dropna():的部分代码示例

# outer merge
df3 = pd.merge(df1,df2, how = 'outer', left_index = True, right_index = True)
#df4 = df3.interpolate(method = 'linear')[1:]
df4 = df3.interpolate(method = 'linear').dropna()
df4

输出:

            A          B
8   -5.982016 -13.827641
10  -6.690969 -12.283885
13  -7.788130 -11.871918
14  -7.877051 -11.459951
38  -7.965972 -11.263787
62  -8.070710 -11.067622
64  -8.175448 -10.745988
65  -8.280187 -10.729109
73 -11.274724 -10.712230
76 -12.270691 -10.695352
80 -13.545215 -10.678473
87 -13.545215 -10.661594
95 -13.545215  -9.816053
97 -13.545215  -7.740810

情节:

enter image description here

完整的数据和代码示例

#imports
import numpy as np
import pandas as pd

# Some sample data
np.random.seed(1)
df1_index = sorted(np.random.randint(1,101,8), reverse = True)
df1info = {'A':sorted((np.random.normal(10, 2, 8))*-1)}

df2_index = sorted(np.random.randint(1,101,8))
df2info = {'B':sorted(np.random.normal(10, 2, 8)*-1)}

# Two dataframes
df1 = pd.DataFrame(df1info, index = df1_index)
df2 = pd.DataFrame(df2info, index = df2_index)

# outer merge
df3 = pd.merge(df1,df2, how = 'outer', left_index = True, right_index = True)

# interpolate missing values
df4 = df3.interpolate(method = 'linear').dropna()

# plot
df4.plot()

谢谢您的任何建议!

编辑1:场景1重复

如果df2.indexdf1.index中有完全匹配项,并且df1.index有重复项,则正确的匹配项是最低的df1.index。我希望这是有道理的。如果由于某种原因被证明是荒谬的,我愿意接受其他建议!

1 个答案:

答案 0 :(得分:2)

不是“ Pythonic”,而是O(n)解决方案

df2_index.sort()
df1_index.sort()

a = 0
b = 0
mapping = [[],[]]
while b < len(df2_index) and a < len(df1_index):
    if df1_index[a] == df2_index[b]:
        mapping[0].append(df2_index[b])
        mapping[1].append(df1.loc[df1_index[a], "A"]) 
        b += 1
        a += 1
    elif df1_index[a] > df2_index[b]:
        mapping[0].append(df2_index[b])
        mapping[1].append(df1.loc[df1_index[a], "A"])           
        b += 1
    else:
        a += 1

df = pd.DataFrame({'A': mapping[1]}, index = mapping[0])
df2.merge(df, left_index=True, right_index=True, how='outer')

输出

     B              A
8   -13.827641  -6.690969
10  -12.283885  -6.690969
14  -11.459951  -7.965972
62  -11.067622  -8.280187
64  -10.745988  -8.280187
87  -10.661594  NaN
95  -9.816053   NaN
97  -7.740810   NaN
  • 两个索引均按升序排序
  • b指向B的索引,a指向A的索引
  • 在任何时间点给定b,我们就会找到下一个最大值a,并在找到它时将其保存
  • 如果b == a,那么我们就完成了这些记录,因此我们继续前进
  • 如果a> b,那么我们喜欢b的值,所以我们移动b。我们不会移动a,因为这也可以成为下一个b的候选人
  • 如果a <b之所以移至a,是因为b的候选对象将在当前a之后,因为它已排序。