看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gr99123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在气候变化研究中,可以按照年份或更长时间范围对各种气象指标(如温度、降水量等)进行分组,计算每组的平均值,并与历史数据进行对比,筛选出异常值,用于分析气候变化趋势和影响。我们本例来研究一下如何利用 pandas 筛选部分列对应平均值的情况。
我们构造数据如下:
import pandas as pd
import io
data = '''
name temp  number     area  value1  value2
   A  10C       1    China       1       8
   A  10C       2    China       3      10
   A  20C       3    China       5       4
   A  30C       4    China       7       6
   B  10C       1  America      12      20
   B  20C       2  America      14      22
   B  30C       3  America      16      24
   B  40C       4  America      18      26
'''
df = pd.read_csv(io.StringIO(data), sep=r'\s+')
df
# ...
我们期望按照 name 列分组,对于 value1 和 value2 两列,大于平均值的保留,小于平均值的舍弃,其他列不变化保留即可。
我们先看看单个列,如 value1 如何实现需求中的逻辑,然后再将它写成批量代码。
我们先对 name 进行分组,然后取分组对象的 value1 列,用 transform() 应用 mean 求得各组的平均值,然后与 value1 进行比较,得到一个布尔序列。
用 where 传入以上布尔序列就将不符合要求的值设置为 Nan 了。
仅 value1 的代码如下:
(
    df.value1
    .where(
        df.value1 > df.groupby('name')
           .value1.transform('mean')
    )
)
'''
0     NaN
1     NaN
2     5.0
3     7.0
4     NaN
5     NaN
6    16.0
7    18.0
Name: value1, dtype: float64
'''
然后根据思路设计成函数,应用到每行:
def func(ser:pd.Series) -> pd.Series:
    if (col:=ser.name) in ['value1', 'value2']:
        ser_gb = df.groupby('name')[col]
        ser_mean = ser_gb.transform('mean')
        return ser.where(ser > ser_mean)
    else:
        return ser
df.apply(func)
'''
  name temp  number     area  value1  value2
0    A  10C       1    China     NaN     8.0
1    A  10C       2    China     NaN    10.0
2    A  20C       3    China     5.0     NaN
3    A  30C       4    China     7.0     NaN
4    B  10C       1  America     NaN     NaN
5    B  20C       2  America     NaN     NaN
6    B  30C       3  America    16.0    24.0
7    B  40C       4  America    18.0    26.0
'''
就完成了需求。
(完)
更新时间:2024-08-18 16:22:51 标签:pandas python 筛选 平均数