基于另一个数据框的条件填充pandas的na值
表格 1
ID | 条件 | 访问者1 | 访问者2 |
---|---|---|---|
1 | aa | nan | nan |
2 | aa | nan | nan |
3 | bb | nan | nan |
4 | bb | nan | nan |
5 | aa | nan | nan |
6 | bb | nan | nan |
7 | aa | nan | nan |
表格 2
姓名 | 条件 | 访问者1 | 访问者2 |
---|---|---|---|
约翰 | aa | 是 | 否 |
玛丽 | aa | 否 | 是 |
鲍勃 | aa | 是 | 是 |
本 | bb | 是 | 是 |
彼得 | bb | 否 | 是 |
表格 1 里列出了条件。
表格 2 列出了条件和访问者的姓名,以及他们的访问权限。也就是说,他们可以访问 1、2 或者两者都可以。
举个例子,约翰可以访问 1,但不能访问 2,所以我们需要和表格 1 的条件匹配。ID 1 的条件是 'aa',所以约翰可以访问1,但他的名字没有填在访问2里,然后继续找其他可以访问的人。玛丽的条件是 'aa',她可以访问 2,所以她的名字填在了访问2里。
鲍勃的条件是 'aa',而 ID 2 的条件也是 'aa'。鲍勃可以访问 1 或 2。因此,他的名字填在了 ID 2 的访问1 和访问2里。
ID 5 里,因为鲍勃是最后一个条件为 'aa' 的名字,所以会再次回到约翰。其他的情况也是一样。
结果表
ID | 条件 | 访问者1 | 访问者2 |
---|---|---|---|
1 | aa | 约翰 | 玛丽 |
2 | aa | 鲍勃 | 鲍勃 |
3 | bb | 本 | 本 |
4 | bb | 本 | 彼得 |
5 | aa | 约翰 | 玛丽 |
6 | bb | 本 | 本 |
7 | aa | 鲍勃 | 鲍勃 |
1 个回答
1
我的想法是利用表2创建一个循环列表
,然后填充表1。我的解决方案是结合使用条件语句和pandas的广播概念。
举个例子,我们想用条件aa
来填充表1
的Access1
列,
- 从
表2
中,符合条件aa
的名字有三个:[John, Mary, Bob]
- 但是根据
Accessor1
列的条件,我们只能用[John, Bob]
来填充表1
1. 将表2的Accessor列转换为dtype bool
,这样我们就可以使用pandas的布尔索引来创建条件
import numpy as np
import pandas as pd
from itertools import cycle
table_1 = pd.DataFrame(
{
"ID": list(range(1, 7)),
"Condition": ['aa', 'aa', 'bb', 'bb', 'aa', 'bb'],
"Access1": [np.nan]*6,
"Access2": [np.nan]*6
}
)
table_2 = pd.DataFrame(
{
"Name": ['John', 'Mary', 'Bob', 'Ben', 'Peter'],
"Condition": ['aa', 'aa', 'aa', 'bb', 'bb'],
"Accessor1": ['Yes', 'No', 'Yes', 'Yes', 'No'],
"Accessor2": ['No', 'Yes', 'Yes', 'Yes', 'Yes']
}
)
table_2['Accessor1'] = table_2['Accessor1'].apply(lambda x: True if x == 'Yes' else False)
table_2['Accessor2'] = table_2['Accessor2'].apply(lambda x: True if x == 'Yes' else False)
2. 创建可以用来填充列的列表
condition_aa = table_2[table_2['Condition'] == 'aa']
condition_bb = table_2[table_2['Condition'] == 'bb']
condition_aa_access1 = condition_aa['Name'][condition_aa['Accessor1']].to_list()
condition_aa_access2 = condition_aa['Name'][condition_aa['Accessor2']].to_list()
condition_bb_access1 = condition_bb['Name'][condition_bb['Accessor1']].to_list()
condition_bb_access2 = condition_bb['Name'][condition_bb['Accessor2']].to_list()
3. 将列表转换为循环列表,这样我们就可以填充需要更多行的列,而我们手头的行数不够
condition_aa_access1_cycle = cycle(condition_aa_access1)
condition_bb_access1_cycle = cycle(condition_bb_access1)
condition_aa_access2_cycle = cycle(condition_aa_access2)
condition_bb_access2_cycle = cycle(condition_bb_access2)
condition_access1 = []
4. 根据条件创建与列大小相同的列表
for i in range(6):
if table_1.loc[i, 'Condition'] == 'aa':
condition_access1.append(next(condition_aa_access1_cycle))
else:
condition_access1.append(next(condition_bb_access1_cycle))
condition_access2 = []
for i in range(6):
if table_1.loc[i, 'Condition'] == 'aa':
condition_access2.append(next(condition_aa_access2_cycle))
else:
condition_access2.append(next(condition_bb_access2_cycle))
5. 最后用上面创建的列表填充空值
table_1.loc[table_1.Access1.isnull(), 'Access1'] = condition_access1
table_1.loc[table_1.Access2.isnull(), 'Access2'] = condition_access2
table_1
结果
ID Condition Access1 Access2
1 aa John Mary
2 aa Bob Bob
3 bb Ben Ben
4 bb Ben Peter
5 aa John Mary
6 bb Ben Ben
注意:这里有很多地方可以优化,欢迎分享完全依赖于pandas概念的新解决方案。