根据Pandas中的行匹配,有条件地使用另一个DataFrame中的值填充列

时间:2017-10-06 21:40:42

标签: python pandas

我发现自己失去了试图解决这个问题(自动化税务文书工作)。我有两个数据框:一个是欧元/美元汇率的季度历史记录,另一个是我自己的发票,例如:

import pandas as pd
import numpy as np

usdeur = [(pd.Timestamp('20170705'),1.1329),
          (pd.Timestamp('20170706'),1.1385),
          (pd.Timestamp('20170707'),1.1412),
          (pd.Timestamp('20170710'),1.1387),
          (pd.Timestamp('20170711'),1.1405),
          (pd.Timestamp('20170712'),1.1449)]
labels = ['Date', 'Rate']
rates = pd.DataFrame.from_records(usdeur, columns=labels)

transactions = [(pd.Timestamp('20170706'), 'PayPal',     'USD', 100, 1),
                (pd.Timestamp('20170706'), 'Fastspring', 'USD', 200, 1),
                (pd.Timestamp('20170709'), 'Fastspring', 'USD', 100, 1),
                (pd.Timestamp('20170710'), 'EU',         'EUR', 100, 1),
                (pd.Timestamp('20170710'), 'PayPal',     'USD', 200, 1)]
labels = ['Date', 'From', 'Currency', 'Amount', 'Rate']
sales =pd.DataFrame.from_records(transactions, columns=labels)

导致:

enter image description here

我需要让sales['Rate']列填充rates['Rate']的正确汇率,也就是说:

  • 如果sales['Currency']'EUR',请不要理会。
  • sales的每一行,找到rates中匹配'Date'的行;获取rates['Rate']非常sales['Rate']值并将其放入'Date'
  • 奖励:如果没有匹配Question: var Question = sequelize.define('Question', { }, { classMethods: { associate: function (models) { // associations can be defined here Question.belongsTo(models.User, { as: 'askerId', foreignKey: 'askerId' }) Question.belongsTo(models.User, { as: 'winnerId', foreignKey: 'winnerId' }) Question.hasMany(models.Suggestion) Question.hasMany(models.TagQuestion) } } }) (例如在假日期间,交易所市场已关闭),请检查上一行,直至找到合适的值。

完整结果应如下所示(请注意第2行的比率为2017-07-07):

Processed result

我试图从其他问题中遵循几个建议的解决方案,但没有运气。 非常感谢您提前

3 个答案:

答案 0 :(得分:2)

您可以更改费率数据框以包含所有日期,然后转发填充,在费率数据框中创建一个名为“货币”的列,然后在日期和时间加入两个df。货币栏。

idx = pd.DataFrame(pd.date_range('2017-07-05', '2017-07-12'),columns=['Date'])
rates = pd.merge(idx,rates,how="left",on="Date")
rates['Currency'] = 'USD'
rates['Rate'] = rates['Rate'].ffill()           

     Date   Rate    Currency
0   2017-07-05  1.1329  USD
1   2017-07-06  1.1385  USD
2   2017-07-07  1.1412  USD
3   2017-07-08  1.1412  USD
4   2017-07-09  1.1412  USD
5   2017-07-10  1.1387  USD
6   2017-07-11  1.1405  USD
7   2017-07-12  1.1449  USD

然后进行左连接将给出:

result = pd.merge(sales,rates,how="left",on=["Currency","Date"])
result['Rate'] = np.where(result['Currency'] == 'EUR', 1, result['Rate_y'])
result = result.drop(['Rate_x','Rate_y'],axis =1)

会给:

     Date         From      Currency    Amount  Rate
0   2017-07-06  PayPal           USD    100 1.1385
1   2017-07-06  Fastspring       USD    200 1.1385
2   2017-07-09  Fastspring       USD    100 1.1412
3   2017-07-10  EU               EUR    100 1.0000
4   2017-07-10  PayPal           USD    200 1.1387

答案 1 :(得分:2)

我使用pd.merge_asof

分解了这些步骤
sales=pd.merge_asof(sales,rates,on='Date',direction='backward',allow_exact_matches =True)
sales.loc[sales.From=='EU','Rate_y']=sales.Rate_x

sales
Out[748]: 
        Date        From Currency  Amount  Rate_x  Rate_y
0 2017-07-06      PayPal      USD     100       1  1.1385
1 2017-07-06  Fastspring      USD     200       1  1.1385
2 2017-07-09  Fastspring      USD     100       1  1.1412
3 2017-07-10          EU      EUR     100       1  1.0000
4 2017-07-10      PayPal      USD     200       1  1.1387

然后

sales.drop('Rate_x',1).rename(columns={'Rate_y':'Rate'})
Out[749]: 
        Date        From Currency  Amount    Rate
0 2017-07-06      PayPal      USD     100  1.1385
1 2017-07-06  Fastspring      USD     200  1.1385
2 2017-07-09  Fastspring      USD     100  1.1412
3 2017-07-10          EU      EUR     100  1.0000
4 2017-07-10      PayPal      USD     200  1.1387

答案 2 :(得分:1)

这是我如何在没有合并的情况下做到这一点。 1.与其他答案一样填写缺少日期和填充的费率,但将日期保留为索引。 2.将此数据框映射到sales,使用loc不包含EUR

的行
idx = pd.date_range(rates['Date'].min(), rates['Date'].max())
rates = rates.set_index('Date').reindex(idx).ffill()
sales.loc[sales['Currency'] != 'EUR','Rate'] = sales.loc[sales['Currency'] != 'EUR','Date'].map(rates['Rate'])

    Date        From        Currency    Amount  Rate
0   2017-07-06  PayPal      USD         100     1.1385
1   2017-07-06  Fastspring  USD         200     1.1385
2   2017-07-09  Fastspring  USD         100     1.1412
3   2017-07-10  EU          EUR         100     1.0000
4   2017-07-10  PayPal      USD         200     1.1387

或者您甚至可以在不更改数据帧速率的情况下执行此操作

mapper = rates.set_index('Date').reindex(sales['Date'].unique()).ffill()['Rate']

sales.loc[sales['Currency'] != 'EUR','Rate'] = sales.loc[sales['Currency'] != 'EUR','Date'].map(mapper)

Timetesting:

wen:       0.011892538983374834
gayatri:   0.13312408898491412
vaishali : 0.009498710976913571