山顶会课程概述¶
- 【数分+开发为主题】,迎合多维度接单
- 课程排期问题
- 课程大致内容
数据分析基本概述¶
什么是数据分析?¶
所谓的数据分析就是使用一些有效的方法和工具对收集到的数据进行处理,从中发现数据的关键趋势或者规律,以便做出合理的决策和提出有针对性的建议。通俗来说,数据分析就是从数据中找到有用的信息来帮助我们做出更明智、更准确的决策。
总之,数据分析是将数据转化为可理解的信息和见解,可为业务提供决策信息、帮助解决问题和提高效率的过程。本质上,所有的决策、战略和规划都需要数据驱动,数据分析在这个过程中起到了突出的作用。
简单一句话描述数据分析:数据分析可以实现数据价值的最大化!
数据分析的技术实现¶
不写代码的实现¶
处理简单或者普通难度的业务逻辑的分析处理
- Excel
- Mysql
- BI工具(PowerBI或者Tableau)
写代码的实现¶
处理普通难度的业务逻辑的分析处理+复杂的业务逻辑处理
- Python
- 数据分析三剑客:Numpy、Pandas和Matplotlib
- 开发环境安装:
- 链接: https://pan.baidu.com/s/1xI-RafNRZKDQPI7WMSmd2A?pwd=6x2v 提取码: 6x2v
- anaconda:数据分析的集成环境(包含了各种数据分析的模块)
Numpy¶
NumPy(Numerical Python)是Python中用于数据分析、机器学习、科学计算的重要工具包,也是python进行科学计算重要基础库之一,多数值运算。
Pandas(重点)¶
Pandas 库是一个免费、开源的第三方 Python 库,是 Python 数据分析和机器学习必不可少的工具之一,它为 Python 数据分析提供了高性能,且易于使用的数据结构,即 Series 和 DataFrame。Pandas 自诞生后被应用于众多的领域,比如金融、统计学、社会科学、建筑工程等。
Pandas 库基于 Python NumPy 库开发而来,因此,它可以与 Python 的科学计算库配合使用。Pandas 提供了两种数据结构,分别是 Series(一维数组结构)与 DataFrame(二维表格结构),这两种数据结构极大地增强的了 Pandas 的数据分析能力。
数据结构介绍:数据存储在不同的数据结构表示的容器中,则可以基于容器的特性对数据进行不同维度的运算处理操作。
Matplotlib¶
matplotlib是一个用于创建可视化图表的Python库。它提供了一组广泛的功能,用于绘制线图、散点图、柱状图、饼图、等高线图、热图等各种类型的图表。
matplotlib是一个功能强大且灵活的库,被广泛应用于数据可视化、科学计算、工程绘图等领域。
图表绘制在数据分析中主要用户进行数据探索和分析结果的展示。
pandas数据分析库¶
Pandas 提供了两种数据结构,分别是 Series(一维数组结构)与 DataFrame(二维数组结构),这两种数据结构极大地增强的了 Pandas 的数据分析能力。
Series¶
概述¶
Series是一种类似与一维数组的对象,由下面两个部分组成:
- values:一组数据
- index:相关的数据索引标签
常见操作¶
- 创建方式
- 由列表创建
- 由字典创建
In [60]:
import pandas as pd
from pandas import Series,DataFrame
In [64]:
s1 = Series(data=[3,3,6,6,8,8,9,9])
s1
Out[64]:
0 3
1 3
2 6
3 6
4 8
5 8
6 9
7 9
dtype: int64
In [62]:
s2 = Series(data={'name':'bobo','salary':10000,'age':30})
s2
Out[62]:
name bobo
salary 10000
age 30
dtype: object
-
Series的索引
- 隐式索引:默认形式的索引(0,1,2….)
- 显示索引:自定义的索引,可以通过index参数设置显示索引
- 显示索引的作用:增加了数据的可读性
In [66]:
s1[[0,2,4]] #通过隐式索引访问元素
Out[66]:
0 3
2 6
4 8
dtype: int64
In [69]:
s2['name']
Out[69]:
'bobo'
- Series的索引和切片
In [73]:
s1[0:3]
Out[73]:
0 3
1 3
2 6
dtype: int64
In [74]:
s2['name':'age']
Out[74]:
name bobo
salary 10000
age 30
dtype: object
-
Series的常用方法
- head(),tail()
- unique(),nunique()
- value_counts()
- isnull(),notnull()
In [76]:
s1.head(3),s1.tail(2) #用来显示前几个或者后几个元素
Out[76]:
(0 3
1 3
2 6
dtype: int64,
6 9
7 9
dtype: int64)
In [78]:
s1.unique() #元素去重
Out[78]:
array([3, 6, 8, 9])
In [79]:
s1.nunique() #统计去重后元素的个数
Out[79]:
4
In [80]:
s1.value_counts() #统计元素出现的次数
Out[80]:
3 2
6 2
8 2
9 2
dtype: int64
In [82]:
#series的运算
s1 + 100 #让s1的每一个元素都加上100
Out[82]:
0 103
1 103
2 106
3 106
4 108
5 108
6 109
7 109
dtype: int64
In [83]:
s3 = Series(data=[1,2,3],index=['a','b','c'])
s3
Out[83]:
a 1
b 2
c 3
dtype: int64
In [84]:
s4 = Series(data=[1,2,3],index=['a','b','d'])
s4
Out[84]:
a 1
b 2
d 3
dtype: int64
In [85]:
s3 + s4 #NAN就是None
#在Series的运算中,只有索引一致的元素可以进行算数运算,否则补空
Out[85]:
a 2.0
b 4.0
c NaN
d NaN
dtype: float64
DataFrame(重要)¶
概述¶
- DataFrame是一个【表格型】的数据结构。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。
- 行索引:index
- 列索引:columns
- 值:values
DataFrame的创建¶
- 字典创建
In [87]:
dic = {
'name':['Tom','Jerry','Jay'],
'age':[10,20,30],
'salary':[2000,3000,4000]
}
table = DataFrame(data=dic)
table
Out[87]:
name | age | salary | |
---|---|---|---|
0 | Tom | 10 | 2000 |
1 | Jerry | 20 | 3000 |
2 | Jay | 30 | 4000 |
DataFrame的常用属性¶
- values,columns,index,shape
In [88]:
table.shape #表格的形状
Out[88]:
(3, 3)
In [89]:
table.values #返回表格所有的值
Out[89]:
array([['Tom', 10, 2000],
['Jerry', 20, 3000],
['Jay', 30, 4000]], dtype=object)
In [90]:
table.index #行索引
Out[90]:
RangeIndex(start=0, stop=3, step=1)
In [91]:
table.columns #列索引
Out[91]:
Index(['name', 'age', 'salary'], dtype='object')
索引操作(重点)¶
- 对行进行索引
- 队列进行索引
- 对元素进行索引
In [93]:
dic = {'names':['jay','tom','jerry'],
'salary':[1000,2000,3000],
'age':[30,40,50]}
df = DataFrame(data=dic,index=['a','b','c'])
df
Out[93]:
names | salary | age | |
---|---|---|---|
a | jay | 1000 | 30 |
b | tom | 2000 | 40 |
c | jerry | 3000 | 50 |
In [94]:
#索引取单列:df[col]
df['age']
Out[94]:
a 30
b 40
c 50
Name: age, dtype: int64
In [95]:
#索引取多列:df[[col1,coln]]
df[['age','names']]
Out[95]:
age | names | |
---|---|---|
a | 30 | jay |
b | 40 | tom |
c | 50 | jerry |
In [96]:
#索引取单行:df.loc/iloc[index]
df.loc['a']
Out[96]:
names jay
salary 1000
age 30
Name: a, dtype: object
In [99]:
df.iloc[0] #iloc后面跟的是隐式索引,loc后面跟显示索引
Out[99]:
names jay
salary 1000
age 30
Name: a, dtype: object
In [100]:
#索引取多行:df.loc/iloc[[index1,indexn]]
df.loc[['b','a']]
Out[100]:
names | salary | age | |
---|---|---|---|
b | tom | 2000 | 40 |
a | jay | 1000 | 30 |
In [102]:
df
Out[102]:
names | salary | age | |
---|---|---|---|
a | jay | 1000 | 30 |
b | tom | 2000 | 40 |
c | jerry | 3000 | 50 |
In [104]:
#索引取元素
df.loc['b','names'] #逗号左边是行,右边是列
Out[104]:
'tom'
切片操作¶
- 批量切行
- 批量切列
In [105]:
#切行
df['a':'c']
Out[105]:
names | salary | age | |
---|---|---|---|
a | jay | 1000 | 30 |
b | tom | 2000 | 40 |
c | jerry | 3000 | 50 |
In [106]:
#切列
df.loc[:,'names':'salary']
Out[106]:
names | salary | |
---|---|---|
a | jay | 1000 |
b | tom | 2000 |
c | jerry | 3000 |
数据查看¶
- 查看DataFrame的概览和统计信息
- head()
- tail()
- info()
- describe()
In [109]:
df.info() #查看表格的基本信息
<class 'pandas.core.frame.DataFrame'>
Index: 3 entries, a to c
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 names 3 non-null object
1 salary 3 non-null int64
2 age 3 non-null int64
dtypes: int64(2), object(1)
memory usage: 204.0+ bytes
In [110]:
df.describe() #对数据表格进行统计描述
Out[110]:
salary | age | |
---|---|---|
count | 3.0 | 3.0 |
mean | 2000.0 | 40.0 |
std | 1000.0 | 10.0 |
min | 1000.0 | 30.0 |
25% | 1500.0 | 35.0 |
50% | 2000.0 | 40.0 |
75% | 2500.0 | 45.0 |
max | 3000.0 | 50.0 |
数据保存与加载¶
csv¶
- to_csv() & read_csv()
In [112]:
#将df数据写入到文件中存储
dic = {'names':['jay','tom','jerry'],
'salary':[1000,2000,3000],
'age':[30,40,50]}
df = pd.DataFrame(data=dic,index=['a','b','c'])
df
Out[112]:
names | salary | age | |
---|---|---|---|
a | jay | 1000 | 30 |
b | tom | 2000 | 40 |
c | jerry | 3000 | 50 |
In [113]:
df.to_csv('./df.csv')
In [114]:
#读取外部文件 ./data/透视表-篮球赛.csv的数据到df表格中
ball = pd.read_csv('data/透视表-篮球赛.csv')
ball
Out[114]:
对手 | 胜负 | 主客场 | 命中 | 投篮数 | 投篮命中率 | 3分命中率 | 篮板 | 助攻 | 得分 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 勇士 | 胜 | 客 | 10 | 23 | 0.435 | 0.444 | 6 | 11 | 27 |
1 | 国王 | 胜 | 客 | 8 | 21 | 0.381 | 0.286 | 3 | 9 | 27 |
2 | 小牛 | 胜 | 主 | 10 | 19 | 0.526 | 0.462 | 3 | 7 | 29 |
3 | 灰熊 | 负 | 主 | 8 | 20 | 0.400 | 0.250 | 5 | 8 | 22 |
4 | 76人 | 胜 | 客 | 10 | 20 | 0.500 | 0.250 | 3 | 13 | 27 |
5 | 黄蜂 | 胜 | 客 | 8 | 18 | 0.444 | 0.400 | 10 | 11 | 27 |
6 | 灰熊 | 负 | 客 | 6 | 19 | 0.316 | 0.222 | 4 | 8 | 20 |
7 | 76人 | 负 | 主 | 8 | 21 | 0.381 | 0.429 | 4 | 7 | 29 |
8 | 尼克斯 | 胜 | 客 | 9 | 23 | 0.391 | 0.353 | 5 | 9 | 31 |
9 | 老鹰 | 胜 | 客 | 8 | 15 | 0.533 | 0.545 | 3 | 11 | 29 |
10 | 爵士 | 胜 | 主 | 19 | 25 | 0.760 | 0.875 | 2 | 13 | 56 |
11 | 骑士 | 胜 | 主 | 8 | 21 | 0.381 | 0.429 | 11 | 13 | 35 |
12 | 灰熊 | 胜 | 主 | 11 | 25 | 0.440 | 0.429 | 4 | 8 | 38 |
13 | 步行者 | 胜 | 客 | 9 | 21 | 0.429 | 0.250 | 5 | 15 | 26 |
14 | 猛龙 | 负 | 主 | 8 | 25 | 0.320 | 0.273 | 6 | 11 | 38 |
15 | 太阳 | 胜 | 客 | 12 | 22 | 0.545 | 0.545 | 2 | 7 | 48 |
16 | 灰熊 | 胜 | 客 | 9 | 20 | 0.450 | 0.500 | 5 | 7 | 29 |
17 | 掘金 | 胜 | 主 | 6 | 16 | 0.375 | 0.143 | 8 | 9 | 21 |
18 | 尼克斯 | 胜 | 主 | 12 | 27 | 0.444 | 0.385 | 2 | 10 | 37 |
19 | 篮网 | 胜 | 主 | 13 | 20 | 0.650 | 0.615 | 10 | 8 | 37 |
20 | 步行者 | 胜 | 主 | 8 | 22 | 0.364 | 0.333 | 8 | 10 | 29 |
21 | 湖人 | 胜 | 客 | 13 | 22 | 0.591 | 0.444 | 4 | 9 | 36 |
22 | 爵士 | 胜 | 客 | 8 | 19 | 0.421 | 0.333 | 5 | 3 | 29 |
23 | 开拓者 | 胜 | 客 | 16 | 29 | 0.552 | 0.571 | 8 | 3 | 48 |
24 | 鹈鹕 | 胜 | 主 | 8 | 16 | 0.500 | 0.400 | 1 | 17 | 26 |
Excel¶
环境安装:
pip install xlrd -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple
- to_excel(filaPath,sheet_name) & read_excel(filaPath,sheet_name)
- sheet_name工作表名称
In [116]:
#读取excel数据:data/运营商数据.xlsx
opt = pd.read_excel('data/运营商数据.xlsx')
opt
Out[116]:
用户号码 | 用户套餐月租 | 入网时间 | 近6个月平均话费 | 近6个月平均使用流量 | 近6个月平均使用语音 | 优惠名称 | 号码品牌 | 用户年龄 | 用户性别 | 是否订购 | 是否参与活动 | 活动开始时间 | 活动结束时间 | 外呼团队 | 外呼时间 | 外呼分钟数 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 56 | 20020209 | 146.2050 | 9090.910500 | 398.3167 | 送3个月会员 | 4G | 55 | 男 | 否 | NaN | NaN | NaN | NaN | 201911 | 91 |
1 | 2 | 50 | 20060424 | 50.0000 | 3980.592767 | 86.9000 | 送3个月会员 | 4G | 51 | 男 | 否 | NaN | NaN | NaN | NaN | 201909 | 28 |
2 | 3 | 50 | 20111206 | 67.1125 | 1706.841767 | 453.0833 | 送3个月会员 | 4G | 36 | 女 | 是 | 会员赠送3个月 | 201909.0 | 202008.0 | 团队D | 201909 | 128 |
3 | 4 | 56 | 20120412 | 99.0000 | 2872.303067 | 41.3500 | 送3个月会员 | 4G | 35 | 女 | 是 | 会员赠送3个月 | 201909.0 | 202008.0 | 团队D | 201909 | 91 |
4 | 5 | 88 | 20150503 | 88.0000 | 28222.901100 | 326.3500 | 送3个月会员 | 4G | 57 | 男 | 是 | 会员赠送3个月 | 201909.0 | 202008.0 | 团队D | 201909 | 99 |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
16493 | 16494 | 49 | 20041014 | 49.0500 | 50.793967 | 57.2000 | 送3个月会员 | 4G | 23 | 女 | 是 | 会员赠送3个月 | 201910.0 | 202009.0 | 团队D | 201910 | 84 |
16494 | 16495 | 9 | 20060310 | 15.4250 | 554.286000 | 56.7667 | 送3个月会员 | 4G | 47 | 女 | 否 | NaN | NaN | NaN | NaN | 201911 | 0 |
16495 | 16496 | 28 | 20020417 | 64.7350 | 0.002900 | 111.8833 | 送3个月会员 | 2G | 61 | 男 | 否 | NaN | NaN | NaN | NaN | 201910 | 34 |
16496 | 16497 | 15 | 20121001 | 18.1750 | 186.963833 | 21.8333 | 送3个月会员 | 2G | 28 | 男 | 否 | NaN | NaN | NaN | NaN | 201910 | 34 |
16497 | 16498 | 19 | 20171103 | 36.2250 | 3839.240000 | 149.6667 | 送3个月会员 | 4G | 37 | 女 | 是 | 会员赠送3个月 | 201910.0 | 202009.0 | 团队D | 201910 | 63 |
16498 rows × 17 columns
In [117]:
opt.shape
Out[117]:
(16498, 17)
In [118]:
#写入数据到excel中
dic = {'names':['jay','tom','jerry'],
'salary':[1000,2000,3000],
'age':[30,40,50]}
df = pd.DataFrame(data=dic,index=['a','b','c'])
df
Out[118]:
names | salary | age | |
---|---|---|---|
a | jay | 1000 | 30 |
b | tom | 2000 | 40 |
c | jerry | 3000 | 50 |
In [119]:
df.to_excel('dic.xlsx')
- 为什么需要将外部文件的数据读取加载到DataFrame表格中呢?
- 将外部文件读取到DataFrame中,我们就可以基于DataFrame自身的特性对数据进行不同维度的运算和处理
sql¶
环境安装:
pip install sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install pymysql -i https://pypi.tuna.tsinghua.edu.cn/simple
- 写入数据到数据库
- from sqlalchemy import create_engine
- 创建链接对象:
- conn = create_engine(‘mysql+pymysql://root:boboadmin@127.0.0.1:3306/spider?charset=UTF8MB4’)
In [122]:
dic = {'names':['jay','tom','jerry'],
'salary':[1000,2000,3000],
'age':[30,40,50]}
df = pd.DataFrame(data=dic)
df
Out[122]:
names | salary | age | |
---|---|---|---|
0 | jay | 1000 | 30 |
1 | tom | 2000 | 40 |
2 | jerry | 3000 | 50 |
In [125]:
from sqlalchemy import create_engine
#创建一个链接对象
#mysql+pymysql://用户名:密码@ip:port/dbName?charset=UTF8MB4
conn = create_engine('mysql+pymysql://root:boboadmin@127.0.0.1:3306/new_spider?charset=UTF8MB4')
df.to_sql(name='tb_df_new',con=conn)
Out[125]:
3
- 读取数据库中的数据
In [126]:
import pymysql
conn = pymysql.Connect(
host = '127.0.0.1', #数据库服务器地址
port = 3306, #数据库端口
user = 'root', #数据库的用户名
password = 'boboadmin', #密码
db = 'new_spider' #数据库名字
)
ret = pd.read_sql('select * from dep',conn)
ret
/Users/zhangxiaobo/opt/arm-anaconda/anaconda3/lib/python3.9/site-packages/pandas/io/sql.py:761: UserWarning: pandas only support SQLAlchemy connectable(engine/connection) ordatabase string URI or sqlite3 DBAPI2 connectionother DBAPI2 objects are not tested, please consider using SQLAlchemy
warnings.warn(
Out[126]:
id | name | |
---|---|---|
0 | 200 | 技术 |
1 | 201 | 人力资源 |
2 | 202 | 销售 |
3 | 203 | 运营 |
股票分析案例¶
In [186]:
import pandas as pd
#可以将本地的文件数据读取到df,./data/600519.xlsx
df = pd.read_excel('data/600519.xlsx')
df.head()
Out[186]:
Unnamed: 0 | date | open | close | high | low | volume | code | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 2015-01-05 | 24.096 | 35.823 | 37.387 | 23.250 | 94515.0 | 600519 |
1 | 1 | 2015-01-06 | 33.532 | 31.560 | 35.860 | 29.914 | 55020.0 | 600519 |
2 | 2 | 2015-01-07 | 29.932 | 27.114 | 33.078 | 24.432 | 54797.0 | 600519 |
3 | 3 | 2015-01-08 | 28.078 | 26.041 | 28.550 | 24.569 | 40525.0 | 600519 |
4 | 4 | 2015-01-09 | 24.805 | 24.723 | 29.687 | 24.541 | 53982.0 | 600519 |
In [187]:
#删除无用的一列
df.drop(columns='Unnamed: 0',inplace=True) #inplace=True将删除操作作用在了原始数据中
In [188]:
df.shape
Out[188]:
(2153, 7)
In [189]:
df.head()
Out[189]:
date | open | close | high | low | volume | code | |
---|---|---|---|---|---|---|---|
0 | 2015-01-05 | 24.096 | 35.823 | 37.387 | 23.250 | 94515.0 | 600519 |
1 | 2015-01-06 | 33.532 | 31.560 | 35.860 | 29.914 | 55020.0 | 600519 |
2 | 2015-01-07 | 29.932 | 27.114 | 33.078 | 24.432 | 54797.0 | 600519 |
3 | 2015-01-08 | 28.078 | 26.041 | 28.550 | 24.569 | 40525.0 | 600519 |
4 | 2015-01-09 | 24.805 | 24.723 | 29.687 | 24.541 | 53982.0 | 600519 |
In [190]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2153 entries, 0 to 2152
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 2153 non-null object
1 open 2153 non-null float64
2 close 2153 non-null float64
3 high 2153 non-null float64
4 low 2153 non-null float64
5 volume 2153 non-null float64
6 code 2153 non-null int64
dtypes: float64(5), int64(1), object(1)
memory usage: 117.9+ KB
In [191]:
#将date列转转换成时间类型
df['date'] = df['date'].astype('datetime64') #astype用作类型转换
In [192]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2153 entries, 0 to 2152
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 2153 non-null datetime64[ns]
1 open 2153 non-null float64
2 close 2153 non-null float64
3 high 2153 non-null float64
4 low 2153 non-null float64
5 volume 2153 non-null float64
6 code 2153 non-null int64
dtypes: datetime64[ns](1), float64(5), int64(1)
memory usage: 117.9 KB
In [193]:
#显示索引优势:可以增加数据的可读性
#将date列作为表格的行索引
df.set_index('date',inplace=True)
In [194]:
df.head()
Out[194]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2015-01-05 | 24.096 | 35.823 | 37.387 | 23.250 | 94515.0 | 600519 |
2015-01-06 | 33.532 | 31.560 | 35.860 | 29.914 | 55020.0 | 600519 |
2015-01-07 | 29.932 | 27.114 | 33.078 | 24.432 | 54797.0 | 600519 |
2015-01-08 | 28.078 | 26.041 | 28.550 | 24.569 | 40525.0 | 600519 |
2015-01-09 | 24.805 | 24.723 | 29.687 | 24.541 | 53982.0 | 600519 |
In [195]:
df.shape
Out[195]:
(2153, 6)
-
计算股票的每日收益率和7日波动率:通过计算收益率和波动率,我们可以评估股票的风险和收益情况。
- 每日收益率:(当日收盘价 – 前一日的收盘价)/ 前一日的收盘价
- shift():将一组数据向前或者前后进行移动
- 7日波动率:对每日收益率数据进行每7日滚动的方差计算
- rolling():设置滚动窗口
- 每日收益率:(当日收盘价 – 前一日的收盘价)/ 前一日的收盘价
In [196]:
df['close'].shift(1) #前日收盘
Out[196]:
date
2015-01-05 NaN
2015-01-06 35.823
2015-01-07 31.560
2015-01-08 27.114
2015-01-09 26.041
...
2023-11-03 1779.500
2023-11-06 1811.240
2023-11-07 1812.000
2023-11-08 1791.170
2023-11-09 1798.340
Name: close, Length: 2153, dtype: float64
In [197]:
#每日收益率:(当日收盘价 - 前一日的收盘价)/ 前一日的收盘价
day_rate = (df['close'] - df['close'].shift(1)) / df['close'].shift(1)
day_rate
Out[197]:
date
2015-01-05 NaN
2015-01-06 -0.119002
2015-01-07 -0.140875
2015-01-08 -0.039574
2015-01-09 -0.050612
...
2023-11-03 0.017836
2023-11-06 0.000420
2023-11-07 -0.011496
2023-11-08 0.004003
2023-11-09 -0.002352
Name: close, Length: 2153, dtype: float64
In [198]:
#7日波动率
day_7_rolling_rate = day_rate.rolling(7).var() #var计算一组数据的方差
day_7_rolling_rate
Out[198]:
date
2015-01-05 NaN
2015-01-06 NaN
2015-01-07 NaN
2015-01-08 NaN
2015-01-09 NaN
...
2023-11-03 0.000457
2023-11-06 0.000442
2023-11-07 0.000513
2023-11-08 0.000510
2023-11-09 0.000525
Name: close, Length: 2153, dtype: float64
- 查找股票的市值最大和最小日
- 市值 = 收盘价 * 成交量
- 找出市值数据中最大最小值下标(市值最大和最小日期)
- idxmax() & idxmin()
In [199]:
#每日市值
day_values = df['close'] * df['volume']
day_values
Out[199]:
date
2015-01-05 3.385811e+06
2015-01-06 1.736431e+06
2015-01-07 1.485766e+06
2015-01-08 1.055312e+06
2015-01-09 1.334597e+06
...
2023-11-03 5.465598e+07
2023-11-06 4.624949e+07
2023-11-07 3.507469e+07
2023-11-08 2.615865e+07
2023-11-09 2.296461e+07
Length: 2153, dtype: float64
In [200]:
#找出市值数据中最大最小值下标(市值最大和最小日期)
day_values.idxmax() #求最大元素下标
Out[200]:
Timestamp('2021-09-27 00:00:00')
In [201]:
day_values.idxmin() #求最小元素下标
Out[201]:
Timestamp('2015-02-02 00:00:00')
- 输出该股票所有收盘比开盘上涨3%以上的日期
- (收盘 – 开盘) / 开盘 > 0.03
In [202]:
ex = (df['close'] - df['open']) / df['open'] > 0.03
ex #想获取所有True对应的索引
Out[202]:
date
2015-01-05 True
2015-01-06 False
2015-01-07 False
2015-01-08 False
2015-01-09 False
...
2023-11-03 False
2023-11-06 False
2023-11-07 False
2023-11-08 False
2023-11-09 False
Length: 2153, dtype: bool
In [203]:
#在DataFrame中,可以使用布尔值作为表格的行索引:就会保留True对应的行数据,忽略False对应的行数据
df.loc[ex] #取出了True对应的行数据(满足要求的行数据)
Out[203]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2015-01-05 | 24.096 | 35.823 | 37.387 | 23.250 | 94515.0 | 600519 |
2015-01-15 | 18.887 | 20.869 | 21.169 | 17.605 | 48585.0 | 600519 |
2015-01-20 | 11.732 | 13.605 | 15.805 | 8.987 | 61022.0 | 600519 |
2015-01-21 | 13.778 | 17.496 | 17.987 | 12.805 | 52674.0 | 600519 |
2015-01-23 | 15.460 | 16.278 | 18.332 | 15.450 | 33084.0 | 600519 |
… | … | … | … | … | … | … |
2022-11-15 | 1484.179 | 1540.179 | 1551.149 | 1473.179 | 56318.0 | 600519 |
2023-01-05 | 1711.089 | 1775.089 | 1775.089 | 1707.089 | 47943.0 | 600519 |
2023-02-20 | 1795.089 | 1849.089 | 1852.889 | 1791.289 | 29669.0 | 600519 |
2023-05-22 | 1664.099 | 1720.089 | 1726.089 | 1664.089 | 41284.0 | 600519 |
2023-07-28 | 1832.000 | 1897.000 | 1900.000 | 1828.010 | 39018.0 | 600519 |
252 rows × 6 columns
In [204]:
df.loc[ex].index #获取了满足要求行数据的行索引
Out[204]:
DatetimeIndex(['2015-01-05', '2015-01-15', '2015-01-20', '2015-01-21',
'2015-01-23', '2015-01-26', '2015-02-03', '2015-02-09',
'2015-02-11', '2015-02-16',
...
'2022-06-10', '2022-06-17', '2022-08-31', '2022-11-01',
'2022-11-04', '2022-11-15', '2023-01-05', '2023-02-20',
'2023-05-22', '2023-07-28'],
dtype='datetime64[ns]', name='date', length=252, freq=None)
-
假如张三从2015年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?
- 分析:
- 买入股票
- 一个完整的年,需要买入12手1200支股票。以购买当期的开盘价进行股票的买卖。
- 卖出股票
- 一个完整的年,需要卖出1200支股票(收盘价为单价)
- 特殊情况:
- 最后一年就是一个特殊的年(因为没有到该年最后一个交易日),只可以买不可以卖,但是手里剩余的股票是需要计算到总收益中。
- 买入股票
resample
函数介绍:pandas
库中的resample
函数主要用于将时间序列数据重新采样到不同的时间频率,例如从按天采样重新采样为按周或按月采样。resample
函数的常用语法如下:- df.resample(rule, …).func()
- 其中,df是一个时间序列数据的DataFrame,rule是指定重采样频率的规则字符串(H小时、W星期、M月、A年等),func是用于聚合数据的函数(例如求和、平均值等)。例如:
- df.resample(‘H’).mean()
- df.resample(‘W’).sum()
- df.resample(‘M’).max()
- 分析:
- 分析计算张三买入股票一共花了多少钱?
In [215]:
#找出每个月的第一个交易日的开盘价
monthly = df.resample('M').first() #取出了每个月第一个交易日对应的行数据
monthly.head(5)
#获取的数据会发现日期是每月最后一天的日期并不是第一个交易日的日期?(无需解决,自身存在的bug),但是行数据是没错
Out[215]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2015-01-31 | 24.096 | 35.823 | 37.387 | 23.250 | 94515.0 | 600519 |
2015-02-28 | 11.269 | 10.641 | 12.078 | 9.441 | 33983.0 | 600519 |
2015-03-31 | 25.169 | 25.105 | 27.896 | 23.532 | 31098.0 | 600519 |
2015-04-30 | 29.923 | 29.296 | 31.314 | 28.514 | 76875.0 | 600519 |
2015-05-31 | 81.405 | 83.505 | 87.169 | 79.005 | 54739.0 | 600519 |
In [216]:
#买入股票的总花费
total_cost = monthly['open'].sum() * 100
total_cost
Out[216]:
10173374.9
- 卖出股票到手多少钱?
In [219]:
yearly = df.resample('A').last() #A表示年
yearly
Out[219]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2015-12-31 | 73.910 | 73.880 | 75.190 | 73.510 | 19673.0 | 600519 |
2016-12-31 | 188.471 | 196.011 | 197.151 | 188.471 | 34687.0 | 600519 |
2017-12-31 | 586.648 | 566.138 | 595.148 | 560.248 | 76038.0 | 600519 |
2018-12-31 | 442.947 | 469.657 | 476.047 | 439.647 | 63678.0 | 600519 |
2019-12-31 | 1077.186 | 1077.186 | 1082.186 | 1070.696 | 22588.0 | 600519 |
2020-12-31 | 1852.211 | 1909.211 | 1910.191 | 1850.211 | 38860.0 | 600519 |
2021-12-31 | 2000.504 | 1980.504 | 2003.484 | 1958.504 | 29665.0 | 600519 |
2022-12-31 | 1710.089 | 1701.089 | 1727.079 | 1701.089 | 25333.0 | 600519 |
2023-12-31 | 1790.110 | 1794.110 | 1799.000 | 1783.000 | 12800.0 | 600519 |
In [220]:
recv = yearly['close'].sum() * 1200
recv
Out[220]:
11721343.2
In [221]:
#计算总收益
recv - total_cost
Out[221]:
1547968.2999999989
数据清洗¶
概述¶
数据清洗是指对原始数据进行处理和转换,以去除无效、重复、缺失或错误的数据,使数据符合分析的要求。
作用和意义¶
- 提高数据质量:
- 通过数据清洗,数据质量得到提升,减少错误分析和错误决策。
- 增加数据可用性:
- 清洗后的数据更加规整和易于使用,提高数据的可用性和可读性。
清洗维度¶
- 缺失值处理:
- 对于缺失的数据,可以删除包含缺失值的行或列或者填充缺失值。
- 重复值处理:
- 识别和删除重复的数据行,避免重复数据对分析结果产生误导。
- 异常值处理:
- 检测和处理异常值,决定是删除、替换或保留异常值。
缺失值清洗¶
缺失值/空值的删除¶
- 伪造缺失值数据
In [222]:
import pandas as pd
from pandas import DataFrame,Series
df = pd.read_csv('./data/none.csv',index_col=0)
df #NAN就是None空白
Out[222]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 22 | 6 | 44.0 | NaN | 11 |
1 | 98 | 88 | 20.0 | 85.0 | 16 |
2 | 19 | 83 | NaN | 84.0 | 46 |
3 | 93 | 64 | 76.0 | NaN | 85 |
4 | 7 | 63 | 20.0 | 21.0 | 45 |
5 | 36 | 19 | 36.0 | NaN | 82 |
6 | 53 | 98 | 7.0 | 89.0 | 1 |
- 缺失值的检测和删除,相关方法:
- isnull():检测df中的每一个元素是否为空值,为空则给该元素返回True,否则返回False
- notnull():检测df中的每一个元素是否为非空值,为非空则给该元素返回True,否则返回False
- any():检测一行或一列布尔值中是否存在一个或多个True,有则返回True,否则返回False
- all():检测一行或一列布尔值中是否存全部为True,有则返回True,否则返回False
- dropna():将存在缺失值/空值的行或者列进行删除
In [223]:
#检测哪些列中存在空值
df.isnull()
Out[223]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | False | False | False | True | False |
1 | False | False | False | False | False |
2 | False | False | True | False | False |
3 | False | False | False | True | False |
4 | False | False | False | False | False |
5 | False | False | False | True | False |
6 | False | False | False | False | False |
In [224]:
df.notnull()
Out[224]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | True | True | True | False | True |
1 | True | True | True | True | True |
2 | True | True | False | True | True |
3 | True | True | True | False | True |
4 | True | True | True | True | True |
5 | True | True | True | False | True |
6 | True | True | True | True | True |
In [226]:
#可以判定哪些列中存在空值
df.isnull().any(axis=0)
#axis=0表示针对列进行any操作
#axis=1表示针对行进行any操作
Out[226]:
0 False
1 False
2 True
3 True
4 False
dtype: bool
In [228]:
df.notnull().all(axis=0)
Out[228]:
0 True
1 True
2 False
3 False
4 True
dtype: bool
- dropna()进行空值检测和过滤
In [240]:
df.dropna() #直接返回删除空值对应行后的结果,不会直接改变原始数据
Out[240]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
1 | 98 | 88 | 20.0 | 85.0 | 16 |
4 | 7 | 63 | 20.0 | 21.0 | 45 |
6 | 53 | 98 | 7.0 | 89.0 | 1 |
- 计算df中每一列存在缺失值的个数和占比
In [238]:
for col in df.columns:
#满足该条件则表示第col列中是存在空值
if df[col].isnull().sum() > 0:
#求出了该列空值的个数
null_count = df[col].isnull().sum()
#求出该列中空值的占比:空值的数量/列的总元素个数
p = format(null_count / df[col].size,'.2%')
print(col,null_count,p)
2 1 14.29%
3 3 42.86%
- 缺失值/空值的填充
-
- fillna(value,method,axis)
- 参数介绍:
- value:给空值填充的值
- method:填充方式,可以为bfill向后填充和ffill向前填充
- axis:填充轴向
-
- 使用任意值填充空值
In [245]:
df.fillna(value=666)
Out[245]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 22 | 6 | 44.0 | 666.0 | 11 |
1 | 98 | 88 | 20.0 | 85.0 | 16 |
2 | 19 | 83 | 666.0 | 84.0 | 46 |
3 | 93 | 64 | 76.0 | 666.0 | 85 |
4 | 7 | 63 | 20.0 | 21.0 | 45 |
5 | 36 | 19 | 36.0 | 666.0 | 82 |
6 | 53 | 98 | 7.0 | 89.0 | 1 |
- 使用近邻值填充空值
In [249]:
df.fillna(axis=0,method='ffill').fillna(axis=0,method='bfill') #bfill
#在竖直方向上,会用空前面的值填充空值
Out[249]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 22 | 6 | 44.0 | 85.0 | 11 |
1 | 98 | 88 | 20.0 | 85.0 | 16 |
2 | 19 | 83 | 20.0 | 84.0 | 46 |
3 | 93 | 64 | 76.0 | 84.0 | 85 |
4 | 7 | 63 | 20.0 | 21.0 | 45 |
5 | 36 | 19 | 36.0 | 21.0 | 82 |
6 | 53 | 98 | 7.0 | 89.0 | 1 |
- 使用相关的统计值填充空值
In [251]:
#可以使用空值列的均值、中位数等统计指标对空值进行填充
for col in df.columns:
if df[col].isnull().sum() > 0:
#计算出空值列对应的均值
mean_value = df[col].mean()
df[col].fillna(value=mean_value,inplace=True)
In [252]:
df
Out[252]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 22 | 6 | 44.000000 | 69.75 | 11 |
1 | 98 | 88 | 20.000000 | 85.00 | 16 |
2 | 19 | 83 | 33.833333 | 84.00 | 46 |
3 | 93 | 64 | 76.000000 | 69.75 | 85 |
4 | 7 | 63 | 20.000000 | 21.00 | 45 |
5 | 36 | 19 | 36.000000 | 69.75 | 82 |
6 | 53 | 98 | 7.000000 | 89.00 | 1 |
注意:实现空值的清洗最好选择删除的方式,如果删除的成本比较高,再选择填充的方式。
重复值清洗¶
- 伪造重复行的数据源
In [253]:
df = pd.read_csv('data/repeat.csv',index_col=0)
df
Out[253]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 7 | 68 | 20 | 14 | 95 |
1 | 70 | 85 | 37 | 72 | 86 |
2 | 79 | 6 | 92 | 24 | 5 |
3 | 0 | 0 | 0 | 0 | 0 |
4 | 56 | 46 | 25 | 14 | 49 |
5 | 0 | 0 | 0 | 0 | 0 |
6 | 66 | 28 | 98 | 14 | 1 |
7 | 0 | 0 | 0 | 0 | 0 |
- 使用duplicated()方法检测重复的行数据
In [255]:
df.duplicated().sum()
Out[255]:
2
- 使用drop_duplicates()方法检测且删除重复的行数据
In [256]:
df.drop_duplicates()
Out[256]:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 7 | 68 | 20 | 14 | 95 |
1 | 70 | 85 | 37 | 72 | 86 |
2 | 79 | 6 | 92 | 24 | 5 |
3 | 0 | 0 | 0 | 0 | 0 |
4 | 56 | 46 | 25 | 14 | 49 |
6 | 66 | 28 | 98 | 14 | 1 |
异常值清洗¶
异常值是分析师和数据科学家常用的术语,因为它需要密切注意,否则可能导致错误的估计。 简单来说,异常值是一个观察值,远远超出了样本中的整体模式。
异常值在统计学上的全称是疑似异常值,也称作离群点,异常值的分析也称作离群点分析。异常值是指样本中出现的“极端值”,数据值看起来异常大或异常小,其分布明显偏离其余的观测值。异常值分析是检验数据中是否存在不合常理的数据。
- 给定条件的异常数据处理
- 自定义一个1000行3列(A,B,C)取值范围为0-1的数据源,然后将C列中的值大于其两倍标准差的异常值进行清洗
In [257]:
data = pd.read_csv('./data/outlier.csv',index_col=0)
data
Out[257]:
A | B | C | |
---|---|---|---|
0 | 0.794514 | 0.337913 | 0.299290 |
1 | 0.596259 | 0.512930 | 0.554369 |
2 | 0.115003 | 0.401490 | 0.669573 |
3 | 0.773007 | 0.547263 | 0.780857 |
4 | 0.469255 | 0.316957 | 0.214900 |
… | … | … | … |
995 | 0.650119 | 0.042532 | 0.405112 |
996 | 0.704271 | 0.317155 | 0.779764 |
997 | 0.138225 | 0.493625 | 0.152215 |
998 | 0.273130 | 0.763846 | 0.031242 |
999 | 0.536671 | 0.674845 | 0.004224 |
1000 rows × 3 columns
In [261]:
#C列的2倍标准差
twice_std = data['C'].std() * 2
twice_std
Out[261]:
0.5705417437083701
In [267]:
#判定异常值
ex = data['C'] > twice_std
ex #True表示为异常值,False表示正常值
Out[267]:
0 False
1 False
2 True
3 True
4 False
...
995 False
996 True
997 False
998 False
999 False
Name: C, Length: 1000, dtype: bool
In [268]:
data.loc[ex] #取出了True对应的行数据(异常值对应的行数据)
Out[268]:
A | B | C | |
---|---|---|---|
2 | 0.115003 | 0.401490 | 0.669573 |
3 | 0.773007 | 0.547263 | 0.780857 |
7 | 0.013230 | 0.419507 | 0.960728 |
8 | 0.858091 | 0.805964 | 0.586865 |
10 | 0.158810 | 0.095586 | 0.775476 |
… | … | … | … |
981 | 0.803646 | 0.791588 | 0.782859 |
989 | 0.534287 | 0.734984 | 0.701372 |
991 | 0.258987 | 0.039801 | 0.751450 |
993 | 0.002957 | 0.939943 | 0.673207 |
996 | 0.704271 | 0.317155 | 0.779764 |
424 rows × 3 columns
In [269]:
drop_indexs = data.loc[ex].index #提取了异常值对应行数据的行索引
drop_indexs
Out[269]:
Int64Index([ 2, 3, 7, 8, 10, 11, 13, 14, 20, 21,
...
964, 965, 972, 975, 978, 981, 989, 991, 993, 996],
dtype='int64', length=424)
In [270]:
#将异常值对应的行从数据表格中进行删除
data.drop(index=drop_indexs)
Out[270]:
A | B | C | |
---|---|---|---|
0 | 0.794514 | 0.337913 | 0.299290 |
1 | 0.596259 | 0.512930 | 0.554369 |
4 | 0.469255 | 0.316957 | 0.214900 |
5 | 0.539357 | 0.107476 | 0.187495 |
6 | 0.385599 | 0.561930 | 0.377683 |
… | … | … | … |
994 | 0.494248 | 0.558101 | 0.128541 |
995 | 0.650119 | 0.042532 | 0.405112 |
997 | 0.138225 | 0.493625 | 0.152215 |
998 | 0.273130 | 0.763846 | 0.031242 |
999 | 0.536671 | 0.674845 | 0.004224 |
576 rows × 3 columns
map映射¶
- 映射就是指给一组数据中的每一个元素绑定一个固定的数据
In [283]:
df = pd.read_csv('./data/map.csv').drop(columns='Unnamed: 0')
df
Out[283]:
name | salary | |
---|---|---|
0 | 张三 | 10000 |
1 | 李四 | 15000 |
2 | 王五 | 21000 |
3 | 张三 | 10000 |
In [286]:
#给每个人起一个英文名,将其作为表格中新的一列存在
dic = {
'张三':'Tom',
'李四':'Jerry',
'王五':'Jay'
}#映射关系表
df['ename'] = df['name'].map(dic)
df
Out[286]:
name | salary | ename | |
---|---|---|---|
0 | 张三 | 10000 | Tom |
1 | 李四 | 15000 | Jerry |
2 | 王五 | 21000 | Jay |
3 | 张三 | 10000 | Tom |
map充当运算工具¶
In [289]:
#将每一个人的税后薪资进行计算:超过5000部分的钱需要缴纳25%的税
def after_sal(s): #参数s就依次表示每一个人的薪资数据
return s - (s-5000)*0.25
df['after_sal'] = df['salary'].map(after_sal)
df
Out[289]:
name | salary | ename | after_sal | |
---|---|---|---|---|
0 | 张三 | 10000 | Tom | 8750.0 |
1 | 李四 | 15000 | Jerry | 12500.0 |
2 | 王五 | 21000 | Jay | 17000.0 |
3 | 张三 | 10000 | Tom | 8750.0 |
排序¶
In [280]:
data = pd.read_csv('./data/outlier.csv',index_col=0)
data.head()
Out[280]:
A | B | C | |
---|---|---|---|
0 | 0.794514 | 0.337913 | 0.299290 |
1 | 0.596259 | 0.512930 | 0.554369 |
2 | 0.115003 | 0.401490 | 0.669573 |
3 | 0.773007 | 0.547263 | 0.780857 |
4 | 0.469255 | 0.316957 | 0.214900 |
In [281]:
data.sort_values(by='C') #默认根据C列中的元素从小到大进行排序
Out[281]:
A | B | C | |
---|---|---|---|
647 | 0.102826 | 0.268895 | 0.000036 |
521 | 0.491587 | 0.767086 | 0.000680 |
599 | 0.560323 | 0.884960 | 0.001386 |
17 | 0.475333 | 0.968809 | 0.002639 |
717 | 0.561099 | 0.596751 | 0.002810 |
… | … | … | … |
913 | 0.575918 | 0.155275 | 0.995703 |
91 | 0.914415 | 0.738960 | 0.996564 |
273 | 0.746750 | 0.470466 | 0.996640 |
67 | 0.803291 | 0.959692 | 0.996780 |
329 | 0.728317 | 0.810622 | 0.998517 |
1000 rows × 3 columns
In [282]:
data.sort_values(by='C',ascending=False) #从大到小排序
Out[282]:
A | B | C | |
---|---|---|---|
329 | 0.728317 | 0.810622 | 0.998517 |
67 | 0.803291 | 0.959692 | 0.996780 |
273 | 0.746750 | 0.470466 | 0.996640 |
91 | 0.914415 | 0.738960 | 0.996564 |
913 | 0.575918 | 0.155275 | 0.995703 |
… | … | … | … |
717 | 0.561099 | 0.596751 | 0.002810 |
17 | 0.475333 | 0.968809 | 0.002639 |
599 | 0.560323 | 0.884960 | 0.001386 |
521 | 0.491587 | 0.767086 | 0.000680 |
647 | 0.102826 | 0.268895 | 0.000036 |
1000 rows × 3 columns
In [292]:
#axis=0表示的行,axis=1表示的是列
data.sort_index(axis=1,ascending=False)
Out[292]:
C | B | A | |
---|---|---|---|
0 | 0.299290 | 0.337913 | 0.794514 |
1 | 0.554369 | 0.512930 | 0.596259 |
2 | 0.669573 | 0.401490 | 0.115003 |
3 | 0.780857 | 0.547263 | 0.773007 |
4 | 0.214900 | 0.316957 | 0.469255 |
… | … | … | … |
995 | 0.405112 | 0.042532 | 0.650119 |
996 | 0.779764 | 0.317155 | 0.704271 |
997 | 0.152215 | 0.493625 | 0.138225 |
998 | 0.031242 | 0.763846 | 0.273130 |
999 | 0.004224 | 0.674845 | 0.536671 |
1000 rows × 3 columns
In [295]:
#手动对列索引进行排列,此处indices表示排列的结果(只能用隐式索引)
#axis=0表示的行,axis=1表示的是列
data.take(indices=[1,0,2],axis=1)
Out[295]:
B | A | C | |
---|---|---|---|
0 | 0.337913 | 0.794514 | 0.299290 |
1 | 0.512930 | 0.596259 | 0.554369 |
2 | 0.401490 | 0.115003 | 0.669573 |
3 | 0.547263 | 0.773007 | 0.780857 |
4 | 0.316957 | 0.469255 | 0.214900 |
… | … | … | … |
995 | 0.042532 | 0.650119 | 0.405112 |
996 | 0.317155 | 0.704271 | 0.779764 |
997 | 0.493625 | 0.138225 | 0.152215 |
998 | 0.763846 | 0.273130 | 0.031242 |
999 | 0.674845 | 0.536671 | 0.004224 |
1000 rows × 3 columns
map运算¶
In [277]:
#计算下面表格中每个人的税后薪资:超过3000部分的钱缴纳50%的税,计算每个人的税后薪资
#加载数据
df = pd.read_csv('./data/fruits.csv').drop(columns='Unnamed: 0')
df
Out[277]:
item | price | color | weight | |
---|---|---|---|---|
0 | Apple | 4.0 | red | 12 |
1 | Banana | 3.0 | yellow | 20 |
2 | Orange | 3.0 | yellow | 50 |
3 | Banana | 2.5 | green | 30 |
4 | Orange | 4.0 | green | 20 |
5 | Apple | 2.0 | green | 44 |
分组聚合¶
- 数据分类处理的核心:
- groupby()函数
- groups属性查看分组情况
In [296]:
#加载数据
df = pd.read_csv('./data/fruits.csv').drop(columns='Unnamed: 0')
df
Out[296]:
item | price | color | weight | |
---|---|---|---|---|
0 | Apple | 4.0 | red | 12 |
1 | Banana | 3.0 | yellow | 20 |
2 | Orange | 3.0 | yellow | 50 |
3 | Banana | 2.5 | green | 30 |
4 | Orange | 4.0 | green | 20 |
5 | Apple | 2.0 | green | 44 |
In [298]:
#想根据不同水果种类对数据进行分组
df.groupby(by='item').groups #使用groupby分组后,调用groups查看分组的结果
Out[298]:
{'Apple': [0, 5], 'Banana': [1, 3], 'Orange': [2, 4]}
In [300]:
#计算不同水果的平均价格
df.groupby(by='item')['price'] #单独取出每组数据的价格数据
mean_price = df.groupby(by='item')['price'].mean()
mean_price
Out[300]:
item
Apple 3.00
Banana 2.75
Orange 3.50
Name: price, dtype: float64
In [304]:
mean_price.to_dict()
Out[304]:
{'Apple': 3.0, 'Banana': 2.75, 'Orange': 3.5}
In [303]:
#将每种水果的平均价格汇总到原始表格中
dic = {
'Apple':3.00,
'Banana':2.75,
'Orange':3.50
}
#dic = mean_price.to_dict()
df['mean_price'] = df['item'].map(dic)
df
Out[303]:
item | price | color | weight | mean_price | |
---|---|---|---|---|---|
0 | Apple | 4.0 | red | 12 | 3.00 |
1 | Banana | 3.0 | yellow | 20 | 2.75 |
2 | Orange | 3.0 | yellow | 50 | 3.50 |
3 | Banana | 2.5 | green | 30 | 2.75 |
4 | Orange | 4.0 | green | 20 | 3.50 |
5 | Apple | 2.0 | green | 44 | 3.00 |
In [311]:
#计算不同颜色水果的最大重量
color_max_weight = df.groupby(by='color')['weight'].max()
color_max_weight
Out[311]:
color
green 44
red 12
yellow 50
Name: weight, dtype: int64
In [312]:
df['max_weight'] = df['color'].map(color_max_weight.to_dict())
df
Out[312]:
item | price | color | weight | mean_price | max_weight | |
---|---|---|---|---|---|---|
0 | Apple | 4.0 | red | 12 | 3.00 | 12 |
1 | Banana | 3.0 | yellow | 20 | 2.75 | 50 |
2 | Orange | 3.0 | yellow | 50 | 3.50 | 50 |
3 | Banana | 2.5 | green | 30 | 2.75 | 44 |
4 | Orange | 4.0 | green | 20 | 3.50 | 44 |
5 | Apple | 2.0 | green | 44 | 3.00 | 44 |
- 对分组后的结果进行多种不同形式的聚合操作
In [315]:
#求每种水果的平均价格和最高价格、最低价格
df.groupby(by='item')['price'].agg(['mean','max','min'])
Out[315]:
mean | max | min | |
---|---|---|---|
item | |||
Apple | 3.00 | 4.0 | 2.0 |
Banana | 2.75 | 3.0 | 2.5 |
Orange | 3.50 | 4.0 | 3.0 |
透视表¶
透视表是一种可以对数据动态排布并且分类汇总的表格格式。或许大多数人都在Excel使用过数据透视表,也体会到它的强大功能,而在pandas中它被称作pivot_table。
In [317]:
df = pd.read_csv('./data/透视表-篮球赛.csv')
df.head(3)
Out[317]:
对手 | 胜负 | 主客场 | 命中 | 投篮数 | 投篮命中率 | 3分命中率 | 篮板 | 助攻 | 得分 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 勇士 | 胜 | 客 | 10 | 23 | 0.435 | 0.444 | 6 | 11 | 27 |
1 | 国王 | 胜 | 客 | 8 | 21 | 0.381 | 0.286 | 3 | 9 | 27 |
2 | 小牛 | 胜 | 主 | 10 | 19 | 0.526 | 0.462 | 3 | 7 | 29 |
In [319]:
#根据胜负字段进行数据的分组,然后对每组数据进行均值计算
df.pivot_table(index='对手',aggfunc='mean')
Out[319]:
3分命中率 | 助攻 | 命中 | 得分 | 投篮命中率 | 投篮数 | 篮板 | |
---|---|---|---|---|---|---|---|
对手 | |||||||
76人 | 0.33950 | 10.00 | 9.0 | 28.00 | 0.4405 | 20.5 | 3.5 |
勇士 | 0.44400 | 11.00 | 10.0 | 27.00 | 0.4350 | 23.0 | 6.0 |
国王 | 0.28600 | 9.00 | 8.0 | 27.00 | 0.3810 | 21.0 | 3.0 |
太阳 | 0.54500 | 7.00 | 12.0 | 48.00 | 0.5450 | 22.0 | 2.0 |
小牛 | 0.46200 | 7.00 | 10.0 | 29.00 | 0.5260 | 19.0 | 3.0 |
尼克斯 | 0.36900 | 9.50 | 10.5 | 34.00 | 0.4175 | 25.0 | 3.5 |
开拓者 | 0.57100 | 3.00 | 16.0 | 48.00 | 0.5520 | 29.0 | 8.0 |
掘金 | 0.14300 | 9.00 | 6.0 | 21.00 | 0.3750 | 16.0 | 8.0 |
步行者 | 0.29150 | 12.50 | 8.5 | 27.50 | 0.3965 | 21.5 | 6.5 |
湖人 | 0.44400 | 9.00 | 13.0 | 36.00 | 0.5910 | 22.0 | 4.0 |
灰熊 | 0.35025 | 7.75 | 8.5 | 27.25 | 0.4015 | 21.0 | 4.5 |
爵士 | 0.60400 | 8.00 | 13.5 | 42.50 | 0.5905 | 22.0 | 3.5 |
猛龙 | 0.27300 | 11.00 | 8.0 | 38.00 | 0.3200 | 25.0 | 6.0 |
篮网 | 0.61500 | 8.00 | 13.0 | 37.00 | 0.6500 | 20.0 | 10.0 |
老鹰 | 0.54500 | 11.00 | 8.0 | 29.00 | 0.5330 | 15.0 | 3.0 |
骑士 | 0.42900 | 13.00 | 8.0 | 35.00 | 0.3810 | 21.0 | 11.0 |
鹈鹕 | 0.40000 | 17.00 | 8.0 | 26.00 | 0.5000 | 16.0 | 1.0 |
黄蜂 | 0.40000 | 11.00 | 8.0 | 27.00 | 0.4440 | 18.0 | 10.0 |
In [323]:
#根据胜负字段进行数据的分组,对分组中的篮板和得分两个字段进行求和运算
df.pivot_table(index='胜负',values=['篮板','得分'],aggfunc='sum')
Out[323]:
得分 | 篮板 | |
---|---|---|
胜负 | ||
胜 | 692 | 108 |
负 | 109 | 19 |
In [322]:
#根据主客场字段进行数据分类后,对分类后的得分字段求最大值、篮板字段求均值和助攻字段求累加和操作
df.pivot_table(index='主客场',aggfunc={'得分':'max','篮板':'mean','助攻':'sum'})
Out[322]:
助攻 | 得分 | 篮板 | |
---|---|---|---|
主客场 | |||
主 | 121 | 56 | 5.333333 |
客 | 116 | 48 | 4.846154 |
In [324]:
#获取所有队主客场的总得分
df.pivot_table(index='主客场',values='得分',aggfunc='sum')
Out[324]:
得分 | |
---|---|
主客场 | |
主 | 397 |
客 | 404 |
In [326]:
#查看主客场下的总得分都是哪些具体球队的得分构成的
df.pivot_table(index='主客场',values='得分',aggfunc='sum',columns='对手')
Out[326]:
对手 | 76人 | 勇士 | 国王 | 太阳 | 小牛 | 尼克斯 | 开拓者 | 掘金 | 步行者 | 湖人 | 灰熊 | 爵士 | 猛龙 | 篮网 | 老鹰 | 骑士 | 鹈鹕 | 黄蜂 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
主客场 | ||||||||||||||||||
主 | 29.0 | NaN | NaN | NaN | 29.0 | 37.0 | NaN | 21.0 | 29.0 | NaN | 60.0 | 56.0 | 38.0 | 37.0 | NaN | 35.0 | 26.0 | NaN |
客 | 27.0 | 27.0 | 27.0 | 48.0 | NaN | 31.0 | 48.0 | NaN | 26.0 | 36.0 | 49.0 | 29.0 | NaN | NaN | 29.0 | NaN | NaN | 27.0 |
In [327]:
#查看主客场下的总得分都是哪些具体球队的得分构成的
df.pivot_table(index='主客场',values='得分',aggfunc='sum',columns='对手',fill_value=0)
Out[327]:
对手 | 76人 | 勇士 | 国王 | 太阳 | 小牛 | 尼克斯 | 开拓者 | 掘金 | 步行者 | 湖人 | 灰熊 | 爵士 | 猛龙 | 篮网 | 老鹰 | 骑士 | 鹈鹕 | 黄蜂 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
主客场 | ||||||||||||||||||
主 | 29 | 0 | 0 | 0 | 29 | 37 | 0 | 21 | 29 | 0 | 60 | 56 | 38 | 37 | 0 | 35 | 26 | 0 |
客 | 27 | 27 | 27 | 48 | 0 | 31 | 48 | 0 | 26 | 36 | 49 | 29 | 0 | 0 | 29 | 0 | 0 | 27 |
In [330]:
#多条件分类汇总操作
df.pivot_table(index=['主客场','对手'],values='得分',aggfunc='sum')
Out[330]:
得分 | ||
---|---|---|
主客场 | 对手 | |
主 | 76人 | 29 |
小牛 | 29 | |
尼克斯 | 37 | |
掘金 | 21 | |
步行者 | 29 | |
灰熊 | 60 | |
爵士 | 56 | |
猛龙 | 38 | |
篮网 | 37 | |
骑士 | 35 | |
鹈鹕 | 26 | |
客 | 76人 | 27 |
勇士 | 27 | |
国王 | 27 | |
太阳 | 48 | |
尼克斯 | 31 | |
开拓者 | 48 | |
步行者 | 26 | |
湖人 | 36 | |
灰熊 | 49 | |
爵士 | 29 | |
老鹰 | 29 | |
黄蜂 | 27 |
- 快捷键:
- 增加cell:a,b
- 删除cell:x
- 运行cell:shift+enter
今日重点:数据清洗、map映射和map充当运算工具、groupby分组聚合、pivot_table透视¶
In [ ]:
pdf有表格 pandas+。。。
手机销量分析案例¶
- 巩固分组聚合操作
In [46]:
#加载数据
import pandas as pd
data = pd.read_excel('./data/Phone.xlsx')
In [47]:
#缺失值处理
In [48]:
#查看不同品牌手机的累计销量和累计销售额,且对累计销量进行降序
In [49]:
#查看不同月份的销量情况,哪些月份销量比较高
In [50]:
#不同年龄段的购买力
In [51]:
#查看不同城市的购买力情况
In [52]:
#查看不同品牌的不同型号的最高和最低价格是多少
美国大选政治现金分析:
- 加载数据
- 查看数据的基本信息
- 指定数据截取,将如下字段的数据进行提取,其他数据舍弃
- cand_nm :候选人姓名
- contbr_nm : 捐赠人姓名
- contbr_st :捐赠人所在州
- contbr_employer : 捐赠人所在公司
- contbr_occupation : 捐赠人职业
- contb_receipt_amt :捐赠数额(美元)
- contb_receipt_dt : 捐款的日期
- 对新数据进行总览,查看是否存在缺失数据
- 用统计学指标快速描述数值型属性的概要。
- 空值处理。可能因为忘记填写或者保密等等原因,相关字段出现了空值,将其填充为NOT PROVIDE
- 异常值处理。将捐款金额<=0的数据删除
- 新建一列为各个候选人所在党派party
- 查看party这一列中有哪些不同的元素
- 统计party列中各个元素出现次数
- 查看各个党派收到的政治献金总数contb_receipt_amt
- 查看具体每天各个党派收到的政治献金总数contb_receipt_amt
- 将表中日期格式转换为’yyyy-mm-dd’。
- 查看老兵(捐献者职业)DISABLED VETERAN主要支持谁
In [11]:
parties = {
'Bachmann, Michelle': 'Republican',
'Romney, Mitt': 'Republican',
'Obama, Barack': 'Democrat',
"Roemer, Charles E. 'Buddy' III": 'Reform',
'Pawlenty, Timothy': 'Republican',
'Johnson, Gary Earl': 'Libertarian',
'Paul, Ron': 'Republican',
'Santorum, Rick': 'Republican',
'Cain, Herman': 'Republican',
'Gingrich, Newt': 'Republican',
'McCotter, Thaddeus G': 'Republican',
'Huntsman, Jon': 'Republican',
'Perry, Rick': 'Republican'
}
months = {'JAN' : 1, 'FEB' : 2, 'MAR' : 3, 'APR' : 4, 'MAY' : 5, 'JUN' : 6,
'JUL' : 7, 'AUG' : 8, 'SEP' : 9, 'OCT': 10, 'NOV': 11, 'DEC' : 12}
In [10]:
#加载数据:usa_election.txt
df = pd.read_csv('./data/usa_election.txt').drop(columns='Unnamed: 0')
df.head()
Out[10]:
cand_nm | contbr_nm | contbr_st | contbr_employer | contbr_occupation | contb_receipt_amt | contb_receipt_dt | |
---|---|---|---|---|---|---|---|
0 | Bachmann, Michelle | HARVEY, WILLIAM | AL | RETIRED | RETIRED | 250.0 | 20-JUN-11 |
1 | Bachmann, Michelle | HARVEY, WILLIAM | AL | RETIRED | RETIRED | 50.0 | 23-JUN-11 |
2 | Bachmann, Michelle | SMITH, LANIER | AL | INFORMATION REQUESTED | INFORMATION REQUESTED | 250.0 | 05-JUL-11 |
3 | Bachmann, Michelle | BLEVINS, DARONDA | AR | NONE | RETIRED | 250.0 | 01-AUG-11 |
4 | Bachmann, Michelle | WARDENBURG, HAROLD | AR | NONE | RETIRED | 300.0 | 20-JUN-11 |
Matplotlib绘图操作¶
- 在数据分析中画图的意义:
- 1.可以将相关的分析结论进行可视化的展示
- 2.通过画图的操作对相关的数据进行探索
In [135]:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['PingFang HK'] #mac系统使用
# plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# windows使用设置微软雅黑字体
- 线形图
- 用于显示数据随变量的变化趋势
In [53]:
df = pd.read_csv('data/CD_Sale.csv').drop(columns='Unnamed: 0')
In [54]:
#所有用户每月的消费总次数
In [55]:
#统计每月的消费人数
- 散点图
- 用于展示两个数值变量之间的关系
In [56]:
#查看每个用户的总消费金额和总消费产品数量之间的关系
- 直方图
- 用于展示一组数据密度的分布情况。它将数据划分为多个相邻的区间,并计算每个区间内数据的频数或频率,然后将这些频数或频率表示为纵向的矩形条,从而形成一个条形图。
In [57]:
#查看每个用户消费次数的分布情况
- 柱状图:
- 用于展示不同类别或组的数据之间的比较和关系
In [58]:
GDP = [36102,38700,14083,25002]
city = ['Beijing','Shanghai','Tianjin','Chongqing']
- 饼图
- 饼图可以显示不同类别或组成部分在整体中的占比,用于传达数据的分布和比例关系。
In [59]:
#简单的饼图
education = [9823, 5601, 3759, 1400, 450]
labels = ['小学', '初中', '高中', '大学', '研究生及以上']
来源链接:https://www.cnblogs.com/fuminer/p/18823565
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
暂无评论内容