提问人:Rishav Ganguly 提问时间:10/20/2023 最后编辑:Rishav Ganguly 更新时间:10/20/2023 访问量:46
如何根据另一个 df 的条件填充 pandas df?
How to populate a pandas df based on conditions from another df?
问:
我考虑了 2 个表:
表 1:
国家 | 年龄 | 标志着 |
---|---|---|
一个 | 25 | 7 |
B | 45 | 8 |
表2:
年龄范围从 | 年龄范围 至 | A国 | B国 |
---|---|---|---|
20 | 30 | ||
40 | 50 |
我想要的输出:
年龄范围从 | 年龄范围 至 | A国 | B国 |
---|---|---|---|
20 | 30 | 7 | 南 |
40 | 50 | 南 | 8 |
这是我尝试过的:
for index,row in table2.iterrows():
table2.loc[index,'Country A'] = table1[(table1['Country']=='A')&
(table1['Age']>=row[0])&
(table1['Age']<=row[1])]['Marks'].values[0]
但这会给出以下错误:index 0 is out of bounds for axis 0 with size 0
我想我可能已经猜到了错误发生的位置: 每当编译器遇到表 2 中的年龄范围时,而表 1 中不存在相应的年龄。
非常感谢对此问题的任何帮助!先谢谢你...
答:
0赞
jezrael
10/20/2023
#1
将 DataFrame.merge
与 DataFrame.pivot
透视一起使用,并按 Series.between
筛选值:df1
out = (df2[['Age Band From','Age Band To']]
.merge(df1.pivot(index='Age', columns='Country', values='Marks')
.add_prefix('Country ').reset_index(), how='cross'))
out = out[out['Age'].between(out['Age Band From'], out['Age Band To'])]
print (out)
Age Band From Age Band To Age Country A Country B
0 20 30 25 7.0 NaN
3 40 50 45 NaN 8.0
对于更通用的解决方案是添加 DataFrame.join
:
print (df2)
Age Band From Age Band To Country A Country B
0 20 30 NaN NaN
1 4 5 NaN NaN
2 20 35 NaN NaN
3 40 50 NaN NaN
cols = ['Age Band From','Age Band To']
out = (df2.reset_index()[cols + ['index']]
.merge(df1.pivot(index='Age', columns='Country', values='Marks')
.add_prefix('Country ').reset_index(), how='cross'))
out = df2[cols].join(out[out['Age'].between(out['Age Band From'], out['Age Band To'])]
.set_index('index').rename_axis(None).filter(like='Country'))
print (out)
Age Band From Age Band To Country A Country B
0 20 30 7.0 NaN
1 4 5 NaN NaN
2 20 35 7.0 NaN
3 40 50 NaN 8.0
1赞
mozway
10/20/2023
#2
pandas 中没有有效的内置解决方案以通用方式执行此操作。交叉合并适用于小型数据帧,但在大型数据集上的效率很差,甚至很糟糕。事实上,由于它具有二次复杂度,这甚至会导致超过几千行的任何内容都会导致 python 崩溃。
一个可靠的选择是使用 pyjanitor
进行透视
然后执行conditional_join
:
# pip install pyjanitor
import janitor
out = (table2[['Age Band From', 'Age Band To']]
.conditional_join(table1.pivot(index='Age', columns='Country', values='Marks')
.add_prefix('Country ').reset_index(),
('Age Band From', 'Age', '<='),
('Age Band To', 'Age', '>='),
how='left'
)
)
输出:
Age Band From Age Band To Age Country A Country B
0 20 30 25 7.0 NaN
1 40 50 45 NaN 8.0
效率比较
对包含随机数据(和重复数据删除)的两个表使用长度:N
或者,如果您只有一对一的映射(即没有重叠的间隔,table2 的每行在 table1 中只有一个匹配项),则可以将 merge_asof
用于纯 pandas 解决方案:
tmp = (table1.pivot(index='Age', columns='Country', values='Marks')
.add_prefix('Country ').reset_index()
.sort_values(by='Age')
)
# merge on left boundary
out = (pd.merge_asof(table2[['Age Band From', 'Age Band To']].reset_index()
.sort_values(by='Age Band From'),
tmp, direction='forward',
left_on='Age Band From', right_on='Age')
.set_index('index').reindex(table2.index)
# hide based on right boundary
.where(lambda d: d.pop('Age').le(d['Age Band To']))
# restore Band data if needed
.combine_first(table2)
)
输出:
Age Band From Age Band To Country A Country B
0 20 30 7.0 NaN
1 40 50 NaN 8.0
评论