看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在数据处理中,源数据可能具有一定便于记录但又复杂的结构,我们在后续使用数据时还需要进一步进行处理。在本例中,要根据一列数据提取出数据中的相关特征,我们来看看 pandas 是如何完成的。
源数据如下:
df = pd.DataFrame({'a': ['6R-5A-4G-7R',
'2A-4G-3A',
'8G',
'1R-9A']
})
df
'''
a
0 6R-5A-4G-7R
1 2A-4G-3A
2 8G
3 1R-9A
'''
以上数据的 a 列是包含复杂信息的字符串类型列。每个值由连字符连接信息,每个信息由数字和字母组成,数字代表此字母的数量,有些行可能包含多个相同字母。
现在的需求是在数据后边增加一些列,每个字母为一列,值为本行对应字母的数量。
如,索引 0 行,增加 R、A、G 三列,值分别是 13(有两个 R,前边的数字需要相加)、5、4。
整体思路是将 a 列处理成一个字典列表,每个字典里 key 为字母,值为数量,然后将这个字典列表用 pd.DataFrame() 构造成新的 DataFrame,然后和源数据合并得到结果。
对 a 列的每个数据进行处理,我们可以写一个函数,用 Series 的 map()
方法来调用。
我们先以索引 0 行的 a 列数据为测试字符串编写处理函数。
# 用连字符拆分为列表
val = '6R-5A-4G-7R'.split('-')
val
# ['6R', '5A', '4G', '7R']
# 将每个字母与前边的字母相乘,得到纯字母
val = [(i[-1])*int(i[:-1]) for i in val]
val
# ['RRRRRR', 'AAAAA', 'GGGG', 'RRRRRRR']
# 将列表所有元素连接为一个字符串
val = ''.join(val)
val
# 'RRRRRRAAAAAGGGGRRRRRRR'
# 构造 Counter 对象
from collections import Counter
val = Counter(val)
val
# Counter({'R': 13, 'A': 5, 'G': 4})
以上构造的 Counter 对象,它可以帮助我们计算字符串(可迭代对象)里元素的个数,形成一个我们想要字典形式。它是字典的一个子类:
isinstance(val, dict)
# True
Counter.mro()
# [collections.Counter, dict, object]
接下来,将以上处理过程封装为一个函数:
from collections import Counter
def func(val: str):
val = val.split('-')
val = [(i[-1])*int(i[:-1]) for i in val]
val = ''.join(val)
val = Counter(val)
return val
a 列应用这个函数并车为列表:
df.a.map(func).to_list()
'''
[Counter({'R': 13, 'A': 5, 'G': 4}),
Counter({'A': 5, 'G': 4}),
Counter({'G': 8}),
Counter({'R': 1, 'A': 9})]
'''
构造为 DataFrame,将空值填充为 0 并转为整型:
right = (
pd.DataFrame(df.a.map(func).to_list())
.fillna(0)
.astype(int)
)
right
'''
R A G
0 13 5 4
1 0 5 4
2 0 0 8
3 1 9 0
'''
这样就生成了右表数据,最后源数据与右表数据合并:
df.merge(right, left_index=True, right_index=True)
'''
a R A G
0 6R-5A-4G-7R 13 5 4
1 2A-4G-3A 0 5 4
2 8G 0 0 8
3 1R-9A 1 9 0
'''
这样就得到我们想要的结果。
(完)
更新时间:Aug. 18, 2024, 4:07 p.m. 标签:pandas python 文本 特征