Python根据复杂条件从第二个数据帧中选择行

时间:2017-07-06 07:58:32

标签: python pandas numpy dataframe

我有两个数据框,一个包含一些购买数据,另一个包含每周日历,例如

df1:
purchased_at  product_id  cost
01-01-2017    1           £10
01-01-2017    2           £8
09-01-2017    1           £10
18-01-2017    3           £12

df2:
week_no  week_start  week_end
1        31-12-2016  06-01-2017
2        07-01-2017  13-01-2017
3        14-01-2017  20-01-2017

我想使用两者中的数据添加一个' week_no'列到df1,它是从df2中选择的,基于" purchase_at' df1中的日期介于" week_start'和' week_end'日期在df2,即

df1:
purchased_at  product_id  cost  week_no
01-01-2017    1           £10   1
01-01-2017    2           £8    1
09-01-2017    1           £10   2
18-01-2017    3           £12   3

我已经搜索了但是我找不到使用两者之间的比较从第二个数据框中提取数据的示例,而且我无法正确应用任何数据我发现的例子,例如

df1.loc[(df1['purchased_at'] < df2['week_end']) & 
        (df1['purchased_at'] > df2['week_start']), df2['week_no']

不成功,ValueError&#39;只能比较标记相同的系列对象&#39;

任何人都可以帮助解决这个问题,或者如果有更好的方法可以达到相同的结果,我会接受建议。

编辑以添加df1的更多详细信息

df1完整数据框标题

purchased_at  purchase_id  product_id  product_name  transaction_id  account_number  cost
01-01-2017    1            1           A             1               AA001           £10
01-01-2017    2            2           B             1               AA001           £8
02-01-2017    3            1           A             2               AA008           £10
03-01-2017    4            3           C             3               AB040           £12
...  
09-01-2017   12            1           A             10              AB102           £10
09-01-2017   13            2           B             11              AB102           £8
...
18-01-2017   20            3           C             15              AA001           £12

因此,purchase_id随每行逐渐增加,product_id和product_name之间的关系为1:1,transaction_id也会逐渐增加,但交易中可能会有多次购买。

2 个答案:

答案 0 :(得分:0)

如果您的数据框架很大,您可以使用此技巧。

将所有记录的完整cartisian产品加入所有记录:

df_out = pd.merge(df1.assign(key=1),df2.assign(key=1),on='key')

接下来过滤掉那些与这种情况下的条件不匹配的记录,其中purchase_at不在week_start和week_end之间

(df_out.query('week_start < purchased_at < week_end')
       .drop(['key','week_start','week_end'], axis=1))

输出:

   purchased_at  product_id cost  week_no 
0    2017-01-01           1  £10        1 
3    2017-01-01           2   £8        1 
7    2017-01-09           1  £10        2 
11   2017-01-18           3  £12        3 

如果你有大型数据帧,那么你可以按照PiRSquared的建议使用这个numpy method

a = df1.purchased_at.values

bh = df2.week_end.values

bl = df2.week_start.values

i, j = np.where((a[:, None] >= bl) & (a[:, None] <= bh))

pd.DataFrame(
    np.column_stack([df1.values[i], df2.values[j]]),
    columns=df1.columns.append(df2.columns)
).drop(['week_start','week_end'],axis=1)

输出:

          purchased_at product_id cost week_no
0  2017-01-01 00:00:00          1  £10       1
1  2017-01-01 00:00:00          2   £8       1
2  2017-01-09 00:00:00          1  £10       2
3  2017-01-18 00:00:00          3  £12       3

答案 1 :(得分:0)

您可以使用time.strftime()从日期中提取周数。如果你想继续计算周数,你需要定义一个零年&#34;作为时间序列的开始并相应地抵消week_no:

]

在这里,我使用import pandas as pd data = {'purchased_at': ['01-01-2017', '01-01-2017', '09-01-2017', '18-01-2017'], 'product_id': [1,2,1,3], 'cost':['£10', '£8', '£10', '£12']} df = pd.DataFrame(data, columns=['purchased_at', 'product_id', 'cost']) def getWeekNo(date, year0): datetime = pd.to_datetime(date, dayfirst=True) year = int(datetime.strftime('%Y')) weekNo = int(datetime.strftime('%U')) return weekNo + 52*(year-year0) df['week_no'] = df.purchased_at.apply(lambda x: getWeekNo(x, 2017)) 将日期字符串从df转换为datetime-object。 pd.to_dateime()会返回年份和strftime('%Y')一周(从第一个星期一开始的第一周。如果星期一应该从星期一开始,请使用strftime('%U')代替)。

这样,您就不需要为周数维护单独的DataFrame。