看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本例当利用 pandas 的滚动窗口(移动窗口、滑动窗口)能力实现一个将当前行变为本行前三行的拼接内容的需求,在实现过程中我们将理解滚动窗口对象以及它的特点。
源数据与构造方法如下:
from io import StringIO
import pandas as pd
data = '''
原始数据
新股,石油气
拟收购,新能源,医药
军工,业绩预增
乡村振兴,有色
医药,军工
物流,环保,芯片
高送转,妖股
中标,工业4.0
消费,金融,券商
5G,汽车,国资,房地产
'''
df = pd.read_csv(StringIO(data))
df
# ...
此数据仅有一列,期望增加新的一列数据,每个数据是当前行及它前两行共三行的拼接内容,结果如下数据所示:
'''
新增数据
新股,石油气
新股,石油气,拟收购,新能源,医药
新股,石油气,拟收购,新能源,医药,军工,业绩预增
拟收购,新能源,医药,军工,业绩预增,乡村振兴,有色
军工,业绩预增,乡村振兴,有色,医药,军工
乡村振兴,有色,医药,军工,物流,环保,芯片
医药,军工,物流,环保,芯片,高送转,妖股
物流,环保,芯片,高送转,妖股,中标,工业4.0
高送转,妖股,中标,工业4.0,消费,金融,券商
中标,工业4.0,消费,金融,券商,5G,汽车,国资,房地产
'''
除了第一行仅为自己,第二行为上一行和自己,这两行不足三行,第三行开始为当前行与新两行的拼接内容,同样用中文逗号隔开。
需求中的数据迭代过程非常符合滚动窗口的形式,我们可以先将此数据生成一个滚动窗口对象,然后将它个组成一个 Series,每个元素就是前三个数据组成的 Series,没错,Series 的值类型也是一个 Series,最后将每个值拼接起来。
还有一个思路是根据用 apply() 按行迭代,用每个行的索引标签来切片取得对应部分数据再进行操作。
根据思路,我们先取得原始数据大小为 3 的滚动窗口对象:
df.原始数据.rolling(3)
# Rolling [window=3,center=False,axis=0,method=single]
滚动窗口对象和分组对象一样,它是一个可迭代对象,也可以应用函数,但在如 apply() 应该函数时,其要求窗口中的值为数字类型,原始数据的值是一个字符串,因此我们不能直接让其应用函数。
来迭代这个对象看看:
for i in df.原始数据.rolling(3):
print(i, end='\n\n')
'''
0 新股,石油气
Name: 原始数据, dtype: object
0 新股,石油气
1 拟收购,新能源,医药
Name: 原始数据, dtype: object
0 新股,石油气
1 拟收购,新能源,医药
2 军工,业绩预增
Name: 原始数据, dtype: object
1 拟收购,新能源,医药
2 军工,业绩预增
3 乡村振兴,有色
Name: 原始数据, dtype: object
2 军工,业绩预增
3 乡村振兴,有色
4 医药,军工
Name: 原始数据, dtype: object
3 乡村振兴,有色
4 医药,军工
5 物流,环保,芯片
Name: 原始数据, dtype: object
4 医药,军工
5 物流,环保,芯片
6 高送转,妖股
Name: 原始数据, dtype: object
5 物流,环保,芯片
6 高送转,妖股
7 中标,工业4.0
Name: 原始数据, dtype: object
6 高送转,妖股
7 中标,工业4.0
8 消费,金融,券商
Name: 原始数据, dtype: object
7 中标,工业4.0
8 消费,金融,券商
9 5G,汽车,国资,房地产
Name: 原始数据, dtype: object
'''
可以看到每个窗口元素是一个 Series,每个 Series 是大小为 3 的滚动值。我们可以将这个窗口对象构造为 Series,注意,此时构造的 Series 每个元素是窗口 Series:
pd.Series(df.原始数据.rolling(3))
# ...
pd.Series(df.原始数据.rolling(3)).map(type)
'''
0 <class 'pandas.core.series.Series'>
1 <class 'pandas.core.series.Series'>
2 <class 'pandas.core.series.Series'>
3 <class 'pandas.core.series.Series'>
4 <class 'pandas.core.series.Series'>
5 <class 'pandas.core.series.Series'>
6 <class 'pandas.core.series.Series'>
7 <class 'pandas.core.series.Series'>
8 <class 'pandas.core.series.Series'>
9 <class 'pandas.core.series.Series'>
dtype: object
'''
然后对这个 Series 中的 Series 利用 map() 调用字符串的 join() 方法来拼接:
pd.Series(df.原始数据.rolling(3)).map(','.join)
'''
0 新股,石油气
1 新股,石油气,拟收购,新能源,医药
2 新股,石油气,拟收购,新能源,医药,军工,业绩预增
3 拟收购,新能源,医药,军工,业绩预增,乡村振兴,有色
4 军工,业绩预增,乡村振兴,有色,医药,军工
5 乡村振兴,有色,医药,军工,物流,环保,芯片
6 医药,军工,物流,环保,芯片,高送转,妖股
7 物流,环保,芯片,高送转,妖股,中标,工业4.0
8 高送转,妖股,中标,工业4.0,消费,金融,券商
9 中标,工业4.0,消费,金融,券商,5G,汽车,国资,房地产
dtype: object
'''
已经得到了新增加数据的内容,最后再将它指定为一个新列:
df.assign(新增数据=pd.Series(df.原始数据.rolling(3)).map(','.join))
'''
原始数据 新增数据
0 新股,石油气 新股,石油气
1 拟收购,新能源,医药 新股,石油气,拟收购,新能源,医药
2 军工,业绩预增 新股,石油气,拟收购,新能源,医药,军工,业绩预增
3 乡村振兴,有色 拟收购,新能源,医药,军工,业绩预增,乡村振兴,有色
4 医药,军工 军工,业绩预增,乡村振兴,有色,医药,军工
5 物流,环保,芯片 乡村振兴,有色,医药,军工,物流,环保,芯片
6 高送转,妖股 医药,军工,物流,环保,芯片,高送转,妖股
7 中标,工业4.0 物流,环保,芯片,高送转,妖股,中标,工业4.0
8 消费,金融,券商 高送转,妖股,中标,工业4.0,消费,金融,券商
9 5G,汽车,国资,房地产 中标,工业4.0,消费,金融,券商,5G,汽车,国资,房地产
'''
根据思路中的索引自动取切片的方法,也可以这么写:
df.apply(lambda x: ','.join(df.原始数据.loc[x.name-(3-1):x.name]), axis=1)
# ...
同样也能得到最终结果,这样我们就完成了这个需求。
(完)
更新时间:2024-08-18 16:08:25 标签:pandas python 拼接 滚动窗口