看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
分组操作是几乎所有数据分析和数据处理无法避免的操作,在今天的案例中,除了对数据分组,还要将分组后的数据拼接再填充到原数据中。我们来看看 pandas 是怎么完成这样的需求的。
源数据如下:
import pandas as pd
df = pd.DataFrame({
'ID': [i for i in range(10)],
'GROUP_CODE': ['G0','G0','G1','G2','G2','G2','G3','G3','G3','G3'],
'sku1':['a','1','b2t','','','','c2c','d2b','e6f',''],
'sku2':['','f','','g','h','','','','',''],
})
df
'''
ID GROUP_CODE sku1 sku2
0 0 G0 a
1 1 G0 1 f
2 2 G1 b2t
3 3 G2 g
4 4 G2 h
5 5 G2
6 6 G3 c2c
7 7 G3 d2b
8 8 G3 e6f
9 9 G3
'''
需求为要以 GROUP_CODE 列为分组,将 sku 开头的列(样例只有两个)进行替换填充。
替换填充的逻辑为按列将同组的所有值赋为此组所有值用 #
号拼接的字符串,如果此组全为空则不填充。
如 sku1 列中:
a#1
c2c#d2b#e6f
接下来我们分析代码思路。
要将数据按列分组然后返回原数据相同长度的值,要用分组对象的 transform() 方法,它能按组处理并返回原形状的数据。
transform() 处理的依然是一个分组后的子 DataFrame 或者子 Series,这里我们按列处理子 Series。
将每个列的计算过程写成一个函数,传入各列 Series,按 GROUP_CODE 分组后用 transform() 传入函数来处理上述的子 Series。
处理子 Series 的逻辑为,将不为空的值筛选出来,用 # 连接为一个字符串,连接可以用 join() 方法。
根据以上思路,其实处理每个列的代码如下,以 sku1 列为例:
df.sku1.groupby(df.GROUP_CODE).transform(lambda x: '#'.join(i for i in x if i!=''))
'''
0 a#1
1 a#1
2 b2t
3
4
5
6 c2c#d2b#e6f
7 c2c#d2b#e6f
8 c2c#d2b#e6f
9 c2c#d2b#e6f
Name: sku1, dtype: object
'''
我们将以上处理过程编写成一个函数:
def func(ser: pd.Series):
if 'sku' in ser.name:
grouped = ser.groupby(df.GROUP_CODE)
val = grouped.transform(lambda x: '#'.join(i for i in x if i!=''))
return val
else:
return ser
上述函数的逻辑为:
我们用 apply() 来应用上述函数,它的返回值会替换掉源数据的各列:
df.apply(func)
'''
ID GROUP_CODE sku1 sku2
0 0 G0 a#1 f
1 1 G0 a#1 f
2 2 G1 b2t
3 3 G2 g#h
4 4 G2 g#h
5 5 G2 g#h
6 6 G3 c2c#d2b#e6f
7 7 G3 c2c#d2b#e6f
8 8 G3 c2c#d2b#e6f
9 9 G3 c2c#d2b#e6f
'''
以上就是我们得到的最终结果,这个思路还可以简单写成以下形式的代码:
func = lambda c: df[c].groupby(df.GROUP_CODE).transform(lambda x: '#'.join(i for i in x if i!=''))
df.apply(lambda c: func(c.name) if 'sku' in c.name else c)
所以,我们就得到了最终的期望数据。
(完)
更新时间:Aug. 18, 2024, 4:01 p.m. 标签:pandas 拼接 替换 填充