本系列文章配套代码获取有以下三种途径:
-
可以在以下网站查看,该网站是使用JupyterLite搭建的web端Jupyter环境,因此无需在本地安装运行环境即可使用,首次运行浏览器需要下载一些配置文件(大约20M):
https://returu.github.io/Python_Data_Analysis/lab/index.html
-
也可以通过百度网盘获取,需要在本地配置代码运行环境,环境配置可以查看【Python基础】2.搭建Python开发环境:
链接: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》翻译整理
—————————————————–
当清除缺失值时,在某些情况下,可以使用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.随机采样和排列:
sample
方法。首先构建一个DaraFrame:
1>>> keys = ["a","b","c","d"]
2>>> nums = list(range(1, 6))
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
8a 4a 3 1.621394
9 2a 1 -1.005494
10 1a 0 -0.416767
11b 3b 7 0.344648
12 1b 5 -0.075493
13 5b 9 1.291099
14c 4c 13 0.472525
15 2c 11 -1.050314
16 5c 14 -1.438527
17d 3d 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
安装 statsmodels
:conda 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
本篇文章来源于微信公众号: 码农设计师