pandas fillna 使用 dict map 和 groupby
pandas fillna using dict map and groupby
我有一个数据如下图:
qty_min qty_max region_min region_max subj region
11 1 10 10 ab UK
21 1 nan 20 ab UK
nan nan nan 30 ab UK
nan 2 nan 34 bc US
nan 2 20 nan bc US
10 nan nan nan bc TZ
11 nan nan 47 de TZ
13 3 109 31 de TZ
df = pd.read_clipboard()
print(df)
我想 fillna()
在每个列中:qty_min
、qty_max
、region_min
、region_max
基于模式。
例如:如果qty_min
和qty_max
列中有NaN
,我们需要fillna()
使用groupby
of subj
和 ffill().bfill()
.
同理,如果region_max
、region_min
中有NaN
,我们需要fillna()
利用region
的groupby
和ffill().bfill()
所以,我尝试了以下方法:
df['qty_min'] = df.groupby(['subj'], sort=False)['qty_min'].apply(lambda x: x.ffill().bfill())
df['qty_max'] = df.groupby(['subj'], sort=False)['qty_max'].apply(lambda x: x.ffill().bfill())
df['region_min'] = df.groupby(['region'], sort=False)['region_min'].apply(lambda x: x.ffill().bfill())
df['region_max'] = df.groupby(['region'], sort=False)['region_max'].apply(lambda x: x.ffill().bfill())
如您所见,这并不优雅。此外,我在实际数据中有 20 多个像这样的列,我想用相同的方式填充它们(groupby
列和 ffill.bfill()
)
我已经手动创建了一个如下所示的 dict
来识别相应的 groupby
列来填充 NaN
。
我愿意修改我们存储此信息的方式。您可以使用任何简单的数据结构。
fillna_dict= {
"subj": ['qty_min','qty_max'],
"region": ['region_min','region_max']
}
有什么优雅高效的方法可以做到这一点吗?
我希望我的输出如下所示:
因为你有不同的条件,你需要有几行。
您要做的是重构代码以重用组和单个函数:
f = lambda x: x.ffill().bfill()
g1 = df.groupby(['subj'], sort=False)
g2 = df.groupby(['region'], sort=False)
df['qty_min'] = g1['qty_min'].apply(f)
df['qty_max'] = g1['qty_max'].apply(f)
df['region_min'] = g2['region_min'].apply(f)
df['region_max'] = g2['region_max'].apply(f)
使用你的词典:
f = lambda x: x.ffill().bfill()
fillna_dict= {
"subj": ['qty_min','qty_max'],
"region": ['region_min','region_max']
}
for k, cols in fillna_dict.items():
df[cols] = df.groupby(df[k])[cols].apply(f)
输出:
qty_min qty_max region_min region_max subj region
0 11.0 1.0 10.0 10.0 ab UK
1 21.0 1.0 10.0 20.0 ab UK
2 21.0 1.0 10.0 30.0 ab UK
3 10.0 2.0 20.0 34.0 bc US
4 10.0 2.0 20.0 34.0 bc US
5 10.0 2.0 109.0 47.0 bc TZ
6 11.0 3.0 109.0 47.0 de TZ
7 13.0 3.0 109.0 31.0 de TZ
尝试在函数中实现:
for k,v in fillna_dict.items():
df[v] = df.groupby([k], sort=False)[v].apply(lambda x: x.ffill().bfill())
输出:
qty_min qty_max region_min region_max subj region
0 11.0 1.0 10.0 10.0 ab UK
1 21.0 1.0 10.0 20.0 ab UK
2 21.0 1.0 10.0 30.0 ab UK
3 10.0 2.0 20.0 34.0 bc US
4 10.0 2.0 20.0 34.0 bc US
5 10.0 2.0 109.0 47.0 bc TZ
6 11.0 3.0 109.0 47.0 de TZ
7 13.0 3.0 109.0 31.0 de TZ
重组你的字典并尝试:
fillna_dict= {"qty_min": "subj",
"qty_max": "subj",
"region_min": "region",
"region_max": "region"
}
df[list(fillna_dict.keys())] = df[list(fillna_dict.keys())].apply(lambda x: df.groupby(fillna_dict[x.name], sort=False)[x.name].ffill().bfill())
>>> df
qty_min qty_max region_min region_max subj region
0 11.0 1.0 10.0 10.0 ab UK
1 21.0 1.0 10.0 20.0 ab UK
2 21.0 1.0 10.0 30.0 ab UK
3 10.0 2.0 20.0 34.0 bc US
4 10.0 2.0 20.0 34.0 bc US
5 10.0 2.0 109.0 47.0 bc TZ
6 11.0 3.0 109.0 47.0 de TZ
7 13.0 3.0 109.0 31.0 de TZ
我有一个数据如下图:
qty_min qty_max region_min region_max subj region
11 1 10 10 ab UK
21 1 nan 20 ab UK
nan nan nan 30 ab UK
nan 2 nan 34 bc US
nan 2 20 nan bc US
10 nan nan nan bc TZ
11 nan nan 47 de TZ
13 3 109 31 de TZ
df = pd.read_clipboard()
print(df)
我想 fillna()
在每个列中:qty_min
、qty_max
、region_min
、region_max
基于模式。
例如:如果qty_min
和qty_max
列中有NaN
,我们需要fillna()
使用groupby
of subj
和 ffill().bfill()
.
同理,如果region_max
、region_min
中有NaN
,我们需要fillna()
利用region
的groupby
和ffill().bfill()
所以,我尝试了以下方法:
df['qty_min'] = df.groupby(['subj'], sort=False)['qty_min'].apply(lambda x: x.ffill().bfill())
df['qty_max'] = df.groupby(['subj'], sort=False)['qty_max'].apply(lambda x: x.ffill().bfill())
df['region_min'] = df.groupby(['region'], sort=False)['region_min'].apply(lambda x: x.ffill().bfill())
df['region_max'] = df.groupby(['region'], sort=False)['region_max'].apply(lambda x: x.ffill().bfill())
如您所见,这并不优雅。此外,我在实际数据中有 20 多个像这样的列,我想用相同的方式填充它们(groupby
列和 ffill.bfill()
)
我已经手动创建了一个如下所示的 dict
来识别相应的 groupby
列来填充 NaN
。
我愿意修改我们存储此信息的方式。您可以使用任何简单的数据结构。
fillna_dict= {
"subj": ['qty_min','qty_max'],
"region": ['region_min','region_max']
}
有什么优雅高效的方法可以做到这一点吗?
我希望我的输出如下所示:
因为你有不同的条件,你需要有几行。
您要做的是重构代码以重用组和单个函数:
f = lambda x: x.ffill().bfill()
g1 = df.groupby(['subj'], sort=False)
g2 = df.groupby(['region'], sort=False)
df['qty_min'] = g1['qty_min'].apply(f)
df['qty_max'] = g1['qty_max'].apply(f)
df['region_min'] = g2['region_min'].apply(f)
df['region_max'] = g2['region_max'].apply(f)
使用你的词典:
f = lambda x: x.ffill().bfill()
fillna_dict= {
"subj": ['qty_min','qty_max'],
"region": ['region_min','region_max']
}
for k, cols in fillna_dict.items():
df[cols] = df.groupby(df[k])[cols].apply(f)
输出:
qty_min qty_max region_min region_max subj region
0 11.0 1.0 10.0 10.0 ab UK
1 21.0 1.0 10.0 20.0 ab UK
2 21.0 1.0 10.0 30.0 ab UK
3 10.0 2.0 20.0 34.0 bc US
4 10.0 2.0 20.0 34.0 bc US
5 10.0 2.0 109.0 47.0 bc TZ
6 11.0 3.0 109.0 47.0 de TZ
7 13.0 3.0 109.0 31.0 de TZ
尝试在函数中实现:
for k,v in fillna_dict.items():
df[v] = df.groupby([k], sort=False)[v].apply(lambda x: x.ffill().bfill())
输出:
qty_min qty_max region_min region_max subj region
0 11.0 1.0 10.0 10.0 ab UK
1 21.0 1.0 10.0 20.0 ab UK
2 21.0 1.0 10.0 30.0 ab UK
3 10.0 2.0 20.0 34.0 bc US
4 10.0 2.0 20.0 34.0 bc US
5 10.0 2.0 109.0 47.0 bc TZ
6 11.0 3.0 109.0 47.0 de TZ
7 13.0 3.0 109.0 31.0 de TZ
重组你的字典并尝试:
fillna_dict= {"qty_min": "subj",
"qty_max": "subj",
"region_min": "region",
"region_max": "region"
}
df[list(fillna_dict.keys())] = df[list(fillna_dict.keys())].apply(lambda x: df.groupby(fillna_dict[x.name], sort=False)[x.name].ffill().bfill())
>>> df
qty_min qty_max region_min region_max subj region
0 11.0 1.0 10.0 10.0 ab UK
1 21.0 1.0 10.0 20.0 ab UK
2 21.0 1.0 10.0 30.0 ab UK
3 10.0 2.0 20.0 34.0 bc US
4 10.0 2.0 20.0 34.0 bc US
5 10.0 2.0 109.0 47.0 bc TZ
6 11.0 3.0 109.0 47.0 de TZ
7 13.0 3.0 109.0 31.0 de TZ