首页Python【Python数据分析】5...

【Python数据分析】50.数据聚合和分组操作——通用拆分-应用-联合2


本系列文章配套代码获取有以下三种途径:

  • 可以在以下网站查看,该网站是使用JupyterLite搭建的web端Jupyter环境,因此无需在本地安装运行环境即可使用,首次运行浏览器需要下载一些配置文件(大约20M):

https://returu.github.io/Python_Data_Analysis/lab/index.html
链接:https://pan.baidu.com/s/1MYkeYeVAIRqbxezQECHwcA?pwd=mnsj 提取码:mnsj
  • 前往GitHub详情页面,单击 code 按钮,选择Download ZIP选项:
https://github.com/returu/Python_Data_Analysis

根据《Python for Data Analysis 3rd Edition》翻译整理

—————————————————–


1.使用指定分组值填充缺失值:

当清除缺失值时,在某些情况下,可以使用dropna去除缺失值,但是在某些情况下,你可能需要使用固定值或从数据派生的某些值填充null(na)值。fillna 是一个可以使用的正确工具。

例如,在这里,以均值填充NA值。

 1>>> df = pd.DataFrame({"data1":[1,2,3,4,5,6],"data2":[7,8,9,10,11,12]})
2>>> df.iloc[[0,2,4],0]=np.nan
3>>> df.iloc[[1,3,5],1]=np.nan
4>>> df
5   data1  data2
60    NaN    7.0
71    2.0    NaN
82    NaN    9.0
93    4.0    NaN
104    NaN   11.0
115    6.0    NaN
12
13>>> s = df["data1"]
14>>> s
150    NaN
161    2.0
172    NaN
183    4.0
194    NaN
205    6.0
21Name: data1, dtype: float64
22
23>>> s.fillna(s.mean())
240    4.0
251    2.0
262    4.0
273    4.0
284    4.0
295    6.0
30Name: data1, dtype: float64
31
32>>> df.fillna(df.mean())
33   data1  data2
340    4.0    7.0
351    2.0    9.0
362    4.0    9.0
373    4.0    9.0
384    4.0   11.0
395    6.0    9.0

假设你需要填充值因组而异。一种方法是对数据进行分组,并将 apply 和一个在每个数据块上都调用 fillna 的函数一起使用。

 1>>> index_keys = ["a","b","c","d","e","f","g","h"]
2>>> group_keys = ["E","E","E","E","W","W","W","W"]
3>>> data = [1,2,3,4,5,6,7,8]
4>>> df = pd.DataFrame({"group_keys":group_keys,
5...                   "data":data},
6...                   index=index_keys)
7>>> df.iloc[[0,2,5,7],1] = np.nan
8>>> df
9  group_keys  data
10a          E   NaN
11b          E   2.0
12c          E   NaN
13d          E   4.0
14e          W   5.0
15f          W   NaN
16g          W   7.0
17h          W   NaN
18
19>>> df.groupby("group_keys").mean()
20            data
21group_keys
22E            3.0
23W            6.0
24
25# 计算组均值的函数
26>>def fill_mean(group):
27...     return group.fillna(group.mean())
28...
29
30# 使用组均值填充 NA 值
31>>> df.groupby("group_keys")[["data"]].apply(fill_mean)
32   data
33a   3.0
34b   2.0
35c   3.0
36d   4.0
37e   5.0
38f   6.0
39g   7.0
40h   6.0

有些情况下,你可能在代码中为每个分组预定义了填充值。此时可以使用每个分组的内置name属性。

 1>>> fill_values = {"E"1"W": -1}
2
3# 使用每个分组的内置name属性获取预定义值
4>>def fill_func(group):
5...     return group.fillna(fill_values[group.name])
6
7
8>>> df.groupby("group_keys")[["data"]].apply(fill_func)
9   data
10a   1.0
11b   2.0
12c   1.0
13d   4.0
14e   5.0
15f  -1.0
16g   7.0
17h  -1.0

2.随机采样和排列:

假设你想从大型数据集中抽取一个随机样本(有或没有放回)用于蒙特卡罗模拟或其他应用。有多种方法可以执行“抽取”,本次使用 Series 的 sample 方法。

首先构建一个DaraFrame:

 1>>> keys = ["a","b","c","d"]
2>>> nums = list(range(16))
3
4>>> index_key = []
5>>> for key in keys:
6...     index_key.extend(str(n)+key for n in nums)
7
8
9>>> data = pd.DataFrame({"data1":np.arange(20),
10...                  "data2":np.random.standard_normal(20)}, index=index_key)
11
12>>> data
13    data1     data2
141a      0 -0.416767
152a      1 -1.005494
163a      2  1.484804
174a      3  1.621394
185a      4  0.228382
191b      5 -0.075493
202b      6 -0.146266
213b      7  0.344648
224b      8  1.349625
235b      9  1.291099
241c     10  0.230844
252c     11 -1.050314
263c     12 -0.072797
274c     13  0.472525
285c     14 -1.438527
291d     15  1.212675
302d     16 -1.477872
313d     17  0.715594
324d     18  0.062885
335d     19  0.485427

如果要从data中随机选择5组数据,可以写成如下方式:

 1>>def sample_func(data,n=5):
2...     return data.sample(n)
3
4
5>>> sample_func(data)
6    data1     data2
75d     19  0.485427
82c     11 -1.050314
93d     17  0.715594
102d     16 -1.477872
111a      0 -0.416767

假设,需要根据索引最后的字母进行分组后,再随机选择数据的话,可以写成如下方式:

 1#  获取索引最后一个字母
2>>def get_char(data):
3...     return data[-1]
4
5# 分组后使用 apply
6>>> data.groupby(get_char).apply(sample_func , n=3)
7      data1     data2
84a      3  1.621394
9  2a      1 -1.005494
10  1a      0 -0.416767
113b      7  0.344648
12  1b      5 -0.075493
13  5b      9  1.291099
144c     13  0.472525
15  2c     11 -1.050314
16  5c     14 -1.438527
173d     17  0.715594
18  5d     19  0.485427
19  1d     15  1.212675

可以通过 group_keys=False 来删除外层索引。

 1>>> data.groupby(get_char , group_keys=False).apply(sample_func , n=3)
2    data1     data2
31a      0 -0.416767
44a      3  1.621394
52a      1 -1.005494
62b      6 -0.146266
75b      9  1.291099
81b      5 -0.075493
91c     10  0.230844
105c     14 -1.438527
113c     12 -0.072797
122d     16 -1.477872
134d     18  0.062885
145d     19  0.485427

3.分组加权:

在 groupby 的 split-apply-combine 范式下,DataFrame的列间操作或两个Series之间的操作是可以实现的。

下面,使用一个包含分组键category和权重值weights的数据集为例,计算分组加权平均值。

 1>>> df = pd.DataFrame({"category": ["a""a""a""a","b""b""b""b"],
2...                    "data": np.arange(0,8),
3...                    "weights": np.arange(8,16)})
4
5
6>>> df
7  category  data  weights
80        a     0        8
91        a     1        9
102        a     2       10
113        a     3       11
124        b     4       12
135        b     5       13
146        b     6       14
157        b     7       15
16
17# 使用np.average 计算加权平均值
18>>def get_wavg(group):
19...     return np.average(group["data"],weights=group["weights"])
20
21# 计算加权平均值→(0*8 + 1*9 + 2*10 +3*11)/(8+9+10+11)
22>>> df.groupby("category").apply(get_wavg)
23category
24a    1.631579
25b    5.592593
26dtype: float64

TIPS:不加权时,np.mean(data)np.average(data)都是计算均值。np.average(data,weights=weights)可以计算加权平均。

4.相关性:

首先生成一个示例数随机数据集:

 1>>> df = pd.DataFrame({"category": ["a""a""a""a","b""b""b""b"],
2...                    "data1": np.arange(0,8),
3...                    "data2": np.random.standard_normal(8),
4...                    "data3": np.random.standard_normal(8)})
5
6
7>>> df
8  category  data1     data2     data3
90        a      0 -1.244852  1.317512
101        a      1 -0.184230  1.010715
112        a      2 -2.385288  0.423003
123        a      3  0.762164 -0.140105
134        b      4  0.895490  0.848708
145        b      5 -1.526583  1.658864
156        b      6 -0.389725 -0.754084
167        b      7  1.529704  0.710057

假设需要计算每列与“data3”列的相关性:

1# 定义计算相关性的函数
2>>def corr_func(group):
3...     return group.corrwith(group["data3"])

根据分组键进行分组,然后使用apply方法:

1>>> df.groupby("category").apply(corr_func)
2             data1     data2  data3
3category
4a        -0.991538 -0.361151    1.0
5b        -0.363535 -0.172016    1.0

5.逐组线性回归:

在与前面示例相同的主题中,只要该函数返回一个 pandas 对象或标量值,就可以使用 groupby 执行更复杂的分组统计分析。

例如,可以定义以下regress 回归函数(使用 statsmodels 计量经济学库),它对每个数据块执行普通最小二乘法 (OLS) 回归。

可以使用 conda 安装 statsmodelsconda install statsmodels

 1>>> df = pd.DataFrame({"category": ["a""a""a""a","b""b""b""b"],
2...                    "Y": np.arange(0,8),
3...                    "X": np.random.standard_normal(8)})
4
5
6>>> df
7  category  Y         X
80        a  0  0.067917
91        a  1 -1.451405
102        a  2 -0.149748
113        a  3  0.148811
124        b  4 -0.646108
135        b  5 -0.333078
146        b  6  1.075328
157        b  7  0.556694
16
17>>> import statsmodels.api as sm
18
19>>def regress(data, yvar=None, xvars=None):
20...     Y = data[yvar]
21...     X = data[xvars]
22...     X["intercept"] = 1.
23...     result = sm.OLS(Y, X).fit()
24...     return result.params
25
26# # 计算 Y 对 X 的分组线性回归
27>>> df.groupby("category").apply(regress, yvar="Y", xvars=["X"])
28                 X  intercept
29category
30a         0.460557   1.659402
31b         1.328545   5.283170


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments