Python Pandas-在包含区间的多索引上建立索引
我有一个熊猫数据帧Python Pandas-在包含区间的多索引上建立索引,python,pandas,indexing,intervals,Python,Pandas,Indexing,Intervals,我有一个熊猫数据帧df1,它有一个由user\u id值和start\u date,end\u dateIntervalIndex组成的多索引。我想根据第二个数据帧df2中的相应值从df1中选择行 数据帧df1和df2如下所示: In [1]: df1 Out [1]: start_date end_date status score user_id
df1
,它有一个由user\u id
值和start\u date
,end\u date
IntervalIndex组成的多索引。我想根据第二个数据帧df2
中的相应值从df1
中选择行
数据帧df1
和df2
如下所示:
In [1]: df1
Out [1]:
start_date end_date status score
user_id
A [2017-03-07, 2017-03-11] 2017-03-07 2017-03-11 S1 1000
[2017-03-12, 2017-04-03] 2017-03-12 2017-04-03 S2 1000
[2017-04-04, 2017-05-21] 2017-04-04 2017-05-21 S1 1000
[2017-05-22, 2222-12-31] 2017-05-22 2222-12-31 S3 1000
B [2018-12-01, 2018-12-22] 2018-12-01 2018-12-22 S1 900
[2018-12-23, 2018-12-28] 2018-12-23 2018-12-28 S2 900
[2018-12-29, 2222-12-31] 2018-12-29 2222-12-31 S1 1500
In [2]: df2
Out [2]:
user_id ref_date
0 A 2017-04-24
1 B 2018-12-25
我感兴趣的是从df1
中选择user\u id
s,它也在df2
中,以及相应的df2.ref\u date
s所在的df1
间隔中。在本例中,我希望得到第三行和第六行
如果我使用一行df2
,我可以通过运行以下命令在df1
中找到相应的行:
In [3]: df1.loc[['A']].index.get_level_values(1).get_indexer([pd.to_datetime('2017-04-24')])
Out [3]: array([2])
有没有一种方法可以使用数组一次完成索引
下面是创建数据帧的代码:
users = {'user_id': ['A','A','A','A', 'B','B','B'],
'start_date': ['2017-03-07', '2017-03-12', '2017-04-04', '2017-05-22', '2018-12-01', '2018-12-23', '2018-12-29'],
'end_date': ['2017-03-11', '2017-04-03', '2017-05-21', '2222-12-31', '2018-12-22', '2018-12-28', '2222-12-31'],
'status': ['S1', 'S2', 'S1', 'S3', 'S1', 'S2', 'S1'],
'score': [1000, 1000, 1000, 1000, 900, 900, 1500]
}
df1 = pd.DataFrame(users, columns = ['user_id', 'start_date', 'end_date', 'status', 'score'])
for col in ['start_date', 'end_date']:
df1[col] = pd.to_datetime(df1[col])
df1.set_index(['user_id', pd.IntervalIndex.from_arrays(df1['start_date'], df1['end_date'], closed='both')], drop=True, inplace=True)
df2 = pd.DataFrame({'user_id': ['A', 'B'],
'ref_date': ['2017-04-24', '2018-12-25']})
df2['ref_date'] = pd.to_datetime(df2['ref_date'])
一种解决方案是合并两个数据帧,然后执行查询:
df1.index.names = ['user_id', 'date_ranges']
df_merged = df1.merge(df2, on='user_id', how='left').\
query('start_date <= ref_date <= end_date')
df_merged.head()
# user_id start_date end_date status score ref_date
# 2 A 2017-04-04 2017-05-21 S1 1000 2017-04-24
# 5 B 2018-12-23 2018-12-28 S2 900 2018-12-25
回答得好+1另外,另一个缺点是您创建了行的笛卡尔积,因此如果您有大量行,您可能会有内存问题。非常感谢!可能是新手问题:
df1
中的一个“选定”行的值如何分配,而不冒修改视图(链式分配)的风险?df\u merged
是一个独立的数据帧,如果您在其中更改任何内容,将不会在df1
中进行更新,通常方法返回一个新的数据帧,但始终检查文档在iloc
中选择行和列,例如df1.iloc[1,df1.columns=='user\u id']=0
请记住iloc
是基于整数的,因此不能按名称选择列,这就是我使用布尔掩码的原因,您还可以使用范围:df1.iloc[[0:2],df1.columns=='user\u id'=0
df1.iloc[df_merged.index].head()
# user_id start_date end_date status score
# A [2017-04-04, 2017-05-21] 2017-04-04 2017-05-21 S1 1000
# B [2018-12-23, 2018-12-28] 2018-12-23 2018-12-28 S2 900