我有两个数据帧,如下所示:
data = [['id', 'r0', 'r1'],
['123', 1, 6],
['436', 9, 26],
['791', 45, 200]]
df = pd.DataFrame(data)
data_2 = [['id', 'r3', 'name'],
['123', 1, 'name_a'],
['436', 12, 'name_f'],
['436', 78, 'name_q'],
['234', 300, 'name_d']]
df_2 = pd.DataFrame(data_2)
我想在 df 上包含两个额外的列,其中包含以下信息:
is_contained
:对/错。它告诉是否有任何值,如果df_2[r3
] 包含在df[id] == df_2[id]
df[r0-r1]
的范围内。例如,在df
的前两个寄存器,它将是 True,在第三个寄存器中,它将是 将为假。name
:如果is_contained为 True,则复制df_2["name"]
.否则,此字符串将为空。
因此,这个简单示例的结果将是:
df
:
0 1 2 3 4
0 id r0 r1 is_contained name
1 123 1 6 True name_a
2 456 9 26 True name_f
3 791 45 200 False
考虑到比我的真实例子,这个计算将包括一个相当大的df
,这将是解决这个问题的有效方法?
如果我理解正确(并假设第一行是列名!),您可以使用pandas.merge_asof
,然后计算"is_contained"列,如果它不符合上限要求,则更新"名称"。
先决条件是,确保数据帧按"r0"和"r3"排序。
(pd
.merge_asof(df, df_2, by='id', left_on='r0', right_on='r3', direction='forward')
.assign(is_contained=lambda d: d['r3'].le(d['r1']),
name=lambda d: d['name'].where(d['is_contained'])
)
#.drop(columns='r3') # optional, to remove merge column
)
输出:
id r0 r1 r3 name is_contained
0 123 1 6 1.0 name_a True
1 436 9 26 12.0 name_f True
2 791 45 200 NaN NaN False
使用的输入:
data = [['123', 1, 6],
['436', 9, 26],
['791', 45, 200]]
df = pd.DataFrame(data, columns=['id', 'r0', 'r1'])
data_2 = [['123', 1, 'name_a'],
['436', 12, 'name_f'],
['436', 78, 'name_q'],
['234', 300, 'name_d']]
df_2 = pd.DataFrame(data_2, columns=['id', 'r3', 'name'])
这成功了
df.to_sql("df", conn, index=False)
df_2.to_sql("df_2", conn, index=False)
query = "SELECT *"
"FROM df "
"LEFT JOIN df_2 "
"ON (df.id = df_2.id AND "
"df_2.r3 >= df.r0 AND "
"df_2.r3 <= df.r1);"
df = pd.read_sql_query(query,conn)