Python基于复杂条件从第二个数据帧中选择行
我有两个数据框,一个带有一些采购数据,另一个带有周历,例如Python基于复杂条件从第二个数据帧中选择行,python,pandas,numpy,dataframe,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-20
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
我想使用这两个数据向df1添加一个“week_no”列,该列根据df1中的“Purchase_at”日期在df2中的“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']
因此,购买id随着每行的增加而递增,产品id和产品名称具有1:1的关系,交易id也会递增,但一个交易中可能有多个购买。如果数据帧太大,可以使用此技巧 将所有记录与所有记录进行完整的cartisian产品连接:
df_out = pd.merge(df1.assign(key=1),df2.assign(key=1),on='key')
下一步筛选出与本例中的条件不匹配的记录,其中购买的时间不在周开始和周结束之间
(df_out.query('week_start < purchased_at < week_end')
.drop(['key','week_start','week_end'], axis=1))
如果您确实有大数据帧,那么您可以按照PiRSquared的建议使用它
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)
您可以使用从日期中提取周数。如果要继续向上计算周数,需要将“零年”定义为时间序列的开始,并相应地抵消周数:
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))
这里,我使用pd.to_dateime()
将df中的日期字符串转换为datetime对象strftime('%Y')
返回年份和strftime('%U')
返回周(一年中的第一周从第一个星期日开始。如果周应从星期一开始,请改用'%W'
)
这样,您就不需要仅为周数维护单独的数据帧。解析
df1
的日期就足够了,因为您为周使用的定义似乎是标准的。因此,请看一看,暂时忘记df2
。在您的查询中,数据帧(通常)具有完全不同的形状。您需要在每个数据帧中构造一个键,您可以在该键上执行操作(在df1中尝试每周的开始日)。加上上面的评论,这应该暗示了一个解决方案。这不是标准定义,因为计数将在未来几年继续,所以明年将是第53-104周,以此类推,这就是为什么我想单独加入它,而不是从一个内置的公式计算它。numpy方法看起来非常有用,但是,每个“购买日期”都会复制完整的“周号”输出,也就是说,我有16行代码,而不是上面的输出:购买日期为产品id。。。周号2017-01-01 1 2017-01-01 1 2017-01-01 1 2 2017-01-01 1 3 2017-01-01 2 1 2017-01-01 2 1。。。我的代码看起来与您的示例相匹配,您是否认为这是哪里出了问题?抱歉,这还不清楚。总之,“购买时间”、“产品id”和“成本”行各复制四次,周无输出为[1,1,2,3,1,1,2,3,1,1,2,3,1,1,2,3,1,1,2,1,1,2,3]Sarah。。。您必须向我提供数据和预期输出,以便我进行故障排除。我唯一的猜测是,也许我们正在使用我们的连接创建一个cartisan产品,并且需要在代码中添加一个附加约束,例如product_id。Scott,感谢您迄今为止的评论和帮助。我已经编辑了我的原始帖子,添加了数据帧df1的所有标题。df2与最初规定的相同。预期输出仍然是根据购买日期向df1添加一列,其中包含相应的周号。如果你还需要什么,请告诉我。
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
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))