Pandas 由另一个 df 的 "join" fillna?
Pandas fillna by "join" of another df?
我有 2 个 DF,一个有 ID,一个有条目。基本上:
ID Val
1 111
2 222
3 333
还有一个缺少一些 Val:
ID Val Other
1 111 123
1 NaN 3
1 111 5
2 222 3553
2 NaN 58
2 222 321
3 NaN 456
我想做的是用第一个 df 中的 Val 值填充第二个 df 中 Val 中的缺失值。所以结果应该是:
ID Val Other
1 111 123
1 111 3
1 111 5
2 222 3553
2 222 58
2 222 321
3 NaN 456
我怎样才能做到这一点?我见过一个类似的用例,但来自同一个 df。当我尝试这个时,我得到一个错误 bc。我的 df 的尺寸当然不匹配。
所以问题是,如何通过“连接”填充我的 NaN 值?
假设您的数据帧是 df1 和 df2:
df2.groupby('ID').apply(lambda s: s.fillna(df1.set_index('ID')['Val'][s.name]))
输出:
Val Other
0 111.0 123
1 111.0 3
2 111.0 5
3 222.0 3553
4 222.0 58
5 222.0 321
解决方案一:
可以合并使用 np.where
:
vals = df2.merge(df1, on=['ID'], how='left', suffixes=['_',''])['Val']
df2['Val'] = np.where(df2['Val'].isna(), vals, df2['Val'])
速度:每个循环 1.87 毫秒 ± 29.4 微秒(7 次运行的平均值 ± 标准偏差,每次 100 次循环)
方案二:
创建映射字典并将值映射到 ID。
dct = df1.set_index('ID').to_dict()['Val']
df2.loc[df2['Val'].isna(), 'Val'] = df2['ID'].map(dct)
速度:每个循环 1.94 毫秒 ± 66.2 微秒(7 次运行的平均值 ± 标准偏差,每次 100 次循环)
示例数据:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'ID': {0: 1, 1: 2}, 'Val': {0: 111, 1: 222}})
df2 = pd.DataFrame({'ID': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2}, 'Val': {0: 111.0, 1: np.nan, 2: 111.0, 3: 222.0, 4: np.nan, 5: 222.0}, 'Other': {0: 123, 1: 3, 2: 5, 3: 3553, 4: 58, 5: 321}})
输出:
ID Val Other
0 1 111.0 123
1 1 111.0 3
2 1 111.0 5
3 2 222.0 3553
4 2 222.0 58
5 2 222.0 321
您可以 merge
第一个 df
到第二个,然后使用 combine_first
填充 NaN
s:
df2 = df2.merge(df1.rename({'Val': 'TrueVal'}, axis=1), how='left')
df2['Val'] = df2['Val'].combine_first(df2['TrueVal'])
df2.drop('TrueVal', inplace=True)
测试数据:
import numpy as np
import pandas as pd
a = pd.DataFrame({"ID": {0: 1, 1: 2}, "Val": {0: 111, 1: 222}})
b = pd.DataFrame(
{
"ID": {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2},
"Val": {0: 111.0, 1: np.NaN, 2: 111.0, 3: 222.0, 4: np.NaN, 5: 222.0},
"Other": {0: 123, 1: 3, 2: 5, 3: 3553, 4: 58, 5: 321},
}
)
那我就用merge:
b.merge(a, on="ID")
输出:
ID Val_x Other Val_y
0 1 111.0 123 111
1 1 NaN 3 111
2 1 111.0 5 111
3 2 222.0 3553 222
4 2 NaN 58 222
5 2 222.0 321 222
使用以下方法清理数据框:
c = b.merge(a, on="ID").drop("Val_x", axis=1).rename(columns={"Val_y": "Val"})
我有 2 个 DF,一个有 ID,一个有条目。基本上:
ID Val
1 111
2 222
3 333
还有一个缺少一些 Val:
ID Val Other
1 111 123
1 NaN 3
1 111 5
2 222 3553
2 NaN 58
2 222 321
3 NaN 456
我想做的是用第一个 df 中的 Val 值填充第二个 df 中 Val 中的缺失值。所以结果应该是:
ID Val Other
1 111 123
1 111 3
1 111 5
2 222 3553
2 222 58
2 222 321
3 NaN 456
我怎样才能做到这一点?我见过一个类似的用例,但来自同一个 df。当我尝试这个时,我得到一个错误 bc。我的 df 的尺寸当然不匹配。
所以问题是,如何通过“连接”填充我的 NaN 值?
假设您的数据帧是 df1 和 df2:
df2.groupby('ID').apply(lambda s: s.fillna(df1.set_index('ID')['Val'][s.name]))
输出:
Val Other
0 111.0 123
1 111.0 3
2 111.0 5
3 222.0 3553
4 222.0 58
5 222.0 321
解决方案一:
可以合并使用 np.where
:
vals = df2.merge(df1, on=['ID'], how='left', suffixes=['_',''])['Val']
df2['Val'] = np.where(df2['Val'].isna(), vals, df2['Val'])
速度:每个循环 1.87 毫秒 ± 29.4 微秒(7 次运行的平均值 ± 标准偏差,每次 100 次循环)
方案二:
创建映射字典并将值映射到 ID。
dct = df1.set_index('ID').to_dict()['Val']
df2.loc[df2['Val'].isna(), 'Val'] = df2['ID'].map(dct)
速度:每个循环 1.94 毫秒 ± 66.2 微秒(7 次运行的平均值 ± 标准偏差,每次 100 次循环)
示例数据:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'ID': {0: 1, 1: 2}, 'Val': {0: 111, 1: 222}})
df2 = pd.DataFrame({'ID': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2}, 'Val': {0: 111.0, 1: np.nan, 2: 111.0, 3: 222.0, 4: np.nan, 5: 222.0}, 'Other': {0: 123, 1: 3, 2: 5, 3: 3553, 4: 58, 5: 321}})
输出:
ID Val Other
0 1 111.0 123
1 1 111.0 3
2 1 111.0 5
3 2 222.0 3553
4 2 222.0 58
5 2 222.0 321
您可以 merge
第一个 df
到第二个,然后使用 combine_first
填充 NaN
s:
df2 = df2.merge(df1.rename({'Val': 'TrueVal'}, axis=1), how='left')
df2['Val'] = df2['Val'].combine_first(df2['TrueVal'])
df2.drop('TrueVal', inplace=True)
测试数据:
import numpy as np
import pandas as pd
a = pd.DataFrame({"ID": {0: 1, 1: 2}, "Val": {0: 111, 1: 222}})
b = pd.DataFrame(
{
"ID": {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2},
"Val": {0: 111.0, 1: np.NaN, 2: 111.0, 3: 222.0, 4: np.NaN, 5: 222.0},
"Other": {0: 123, 1: 3, 2: 5, 3: 3553, 4: 58, 5: 321},
}
)
那我就用merge:
b.merge(a, on="ID")
输出:
ID Val_x Other Val_y
0 1 111.0 123 111
1 1 NaN 3 111
2 1 111.0 5 111
3 2 222.0 3553 222
4 2 NaN 58 222
5 2 222.0 321 222
使用以下方法清理数据框:
c = b.merge(a, on="ID").drop("Val_x", axis=1).rename(columns={"Val_y": "Val"})