查找Pandas数据框比较不同大小的数据框。

4

I have two pandas df that look like this

df1
   Amount   Price
0    5       50
1    10      53 
2    15      55
3    30      50
4    45      61

df2 
     Used amount
 0      4.5
 1      1.2
 2      6.2
 3      4.1 
 4      25.6
 5      31
 6      19
 7      15  

我正在尝试在df2中插入一个新列,该列将提供来自df1的价格,df1和df2具有不同的大小,df1较小。

我期望得到类似于这样的结果:

df3 
     Used amount price
 0      4.5       50
 1      1.2       50
 2      6.2       53
 3      4.1       50
 4      25.6      50
 5      31        61
 6      19        50
 7      15        55

我在考虑用类似这样的函数来解决这个问题。
def price_function(key, table):
    used_amount_df2 = (row[0] for row in df1)
    price = filter(lambda x: x < key, used_amount_df1)
4个回答

2
这里是我的解决方案:
第一种方法:
from itertools import product
import pandas as pd
df2=df2.reset_index()
DF=pd.DataFrame(list(product(df2.Usedamount, df1.Amount)), columns=['l1', 'l2'])
DF['DIFF']=(DF.l1-DF.l2)
DF=DF.loc[DF.DIFF<=0,]
DF=DF.sort_values(['l1','DIFF'],ascending=[True,False]).drop_duplicates(['l1'],keep='first')
df1.merge(DF,left_on='Amount',right_on='l2',how='left').merge(df2,left_on='l1',right_on='Usedamount',how='right').loc[:,['index','Usedamount','Price']].set_index('index').sort_index()


Out[185]: 
       Usedamount  Price
index                   
0             4.5     50
1             1.2     50
2             6.2     53
3             4.1     50
4            25.6     50
5            31.0     61
6            19.0     50
7            15.0     55

第二种方法是使用pd.merge_asof,我推荐这种方法。

df2=df2.rename({'Used amount':Amount}).sort_values('Amount')
df2=df2.reset_index()
  pd.merge_asof(df2,df1,on='Amount',allow_exact_matches=True,direction='forward')\
   .set_index('index').sort_index()

Out[206]: 
       Amount  Price
index               
0         4.5     50
1         1.2     50
2         6.2     53
3         4.1     50
4        25.6     50
5        31.0     61
6        19.0     50
7        15.0     55

@rriveral 很高兴能帮到你~ - BENY
非常感谢!我已经使用我的数据集尝试了一下,它可以工作。不过,示例df2中使用的amount数据是一个月的数据,而df1中的数据是一周的数据,因此我需要使用 4 x df1 每个 x 1 df2。 - rriveral
我已经检查了 pd.merge_asof,但我认为它没有这样的选项,您建议按周切割数据集并进行迭代,还是您认为有一个可以与 merge_asof 合并的 df 迭代选项? - rriveral
@rriveral 抱歉我没太理解,你的意思是要进行金额合并,对吧?所以你需要按月份合并,使用 pd.concat - BENY
很抱歉有误解,基本上我想做的事情,以及merge_asof正在做的事情,是将amount used = 4.5与在0至5范围内的值进行匹配,然后分配一个价格,因此amount used是一个包含整个月份大量列表,但当它与另一个表合并时,分配的价格只适用于月份中的一周,因此如果连接了几周,你所说的就有意义了,但您认为可以通过条件匹配日期来完成这个任务吗? - rriveral
@rriveral,没有数据的情况下,我只能粗略地说,“pd.concat”是第一选择,“pd.merge_asof”可以使用“left_on = ['date','amount']”。 - BENY

1

您可以使用 cutsearchsorted 来创建区间。

注意:在 df1 中的索引必须是默认的 - 0,1,2...

#create default index if necessary
df1 = df1.reset_index(drop=True)

#create bins
bins = [0] + df1['Amount'].tolist()
#get index values of df1 by values of Used amount
a = pd.cut(df2['Used amount'], bins=bins, labels=df1.index)
#assign output
df2['price'] = df1['Price'].values[a]
print (df2)
   Used amount  price
0          4.5     50
1          1.2     50
2          6.2     53
3          4.1     50
4         25.6     50
5         31.0     61
6         19.0     50
7         15.0     55

a = df1['Amount'].searchsorted(df2['Used amount'])
df2['price'] = df1['Price'].values[a]
print (df2)
   Used amount  price
0          4.5     50
1          1.2     50
2          6.2     53
3          4.1     50
4         25.6     50
5         31.0     61
6         19.0     50
7         15.0     55

这也是我最先想到的事情。 - piRSquared
1
@piRSquared 只是想分享 pd.merge_asof :) - BENY
1
@Wen 当然可以。我已经有一段时间没有使用过那个了。 - piRSquared

1
使用pd.IntervalIndex,您可以:
In [468]: df1.index = pd.IntervalIndex.from_arrays(df1.Amount.shift().fillna(0),df1.Amount)

In [469]: df1
Out[469]:
              Amount  Price
(0.0, 5.0]         5     50
(5.0, 10.0]       10     53
(10.0, 15.0]      15     55
(15.0, 30.0]      30     50
(30.0, 45.0]      45     61

In [470]: df2['price'] = df2['Used amount'].map(df1.Price)

In [471]: df2
Out[471]:
   Used amount  price
0          4.5     50
1          1.2     50
2          6.2     53
3          4.1     50
4         25.6     50
5         31.0     61
6         19.0     50
7         15.0     55

1
你可以使用 pd.DataFrame.reindex 并设置 method=bfill
df1.set_index('Amount').reindex(df2['Used amount'], method='bfill')

             Price
Used amount       
4.5             50
1.2             50
6.2             53
4.1             50
25.6            50
31.0            61
19.0            50
15.0            55

将其添加到新列中,我们可以使用

join


df2.join(
    df1.set_index('Amount').reindex(df2['Used amount'], method='bfill'),
    on='Used amount'
)

   Used amount  Price
0          4.5     50
1          1.2     50
2          6.2     53
3          4.1     50
4         25.6     50
5         31.0     61
6         19.0     50
7         15.0     55

或者 assign
df2.assign(
    Price=df1.set_index('Amount').reindex(df2['Used amount'], method='bfill').values)

   Used amount  Price
0          4.5     50
1          1.2     50
2          6.2     53
3          4.1     50
4         25.6     50
5         31.0     61
6         19.0     50
7         15.0     55

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接