窟聿湎 发表于 2025-6-6 09:52:23

day01:pandas数据分析

 
山顶会课程概述¶


[*]【数分+开发为主题】,迎合多维度接单
[*]课程排期问题
[*]课程大致内容
  数据分析基本概述¶

  什么是数据分析?¶

  所谓的数据分析就是使用一些有效的方法和工具对收集到的数据进行处理,从中发现数据的关键趋势或者规律,以便做出合理的决策和提出有针对性的建议。通俗来说,数据分析就是从数据中找到有用的信息来帮助我们做出更明智、更准确的决策。 https://img2024.cnblogs.com/blog/2867340/202504/2867340-20250413191806011-1102061161.png
  总之,数据分析是将数据转化为可理解的信息和见解,可为业务提供决策信息、帮助解决问题和提高效率的过程。本质上,所有的决策、战略和规划都需要数据驱动,数据分析在这个过程中起到了突出的作用。
  简单一句话描述数据分析:数据分析可以实现数据价值的最大化!
  数据分析的技术实现¶

  不写代码的实现¶

处理简单或者普通难度的业务逻辑的分析处理
  

[*]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 :import pandas as pd
from pandas import Series,DataFrame In :s1 = Series(data=)
s1 Out:0    3
1    3
2    6
3    6
4    8
5    8
6    9
7    9
dtype: int64 In :s2 = Series(data={'name':'bobo','salary':10000,'age':30})
s2 Out:name       bobo
salary    10000
age          30
dtype: object  

[*]Series的索引

[*]隐式索引:默认形式的索引(0,1,2....)
[*]显示索引:自定义的索引,可以通过index参数设置显示索引

[*]显示索引的作用:增加了数据的可读性


 In :s1[] #通过隐式索引访问元素 Out:0    3
2    6
4    8
dtype: int64 In :s2['name'] Out:'bobo'  

[*]Series的索引和切片
 In :s1 Out:0    3
1    3
2    6
dtype: int64 In :s2['name':'age'] Out:name       bobo
salary    10000
age          30
dtype: object  

[*]Series的常用方法

[*]head(),tail()
[*]unique(),nunique()
[*]value_counts()
[*]isnull(),notnull()

 In :s1.head(3),s1.tail(2) #用来显示前几个或者后几个元素 Out:(0    3
1    3
2    6
dtype: int64,
6    9
7    9
dtype: int64) In :s1.unique() #元素去重 Out:array() In :s1.nunique() #统计去重后元素的个数 Out:4 In :s1.value_counts() #统计元素出现的次数 Out:3    2
6    2
8    2
9    2
dtype: int64 In :#series的运算
s1 + 100 #让s1的每一个元素都加上100 Out:0    103
1    103
2    106
3    106
4    108
5    108
6    109
7    109
dtype: int64 In :s3 = Series(data=,index=['a','b','c'])
s3 Out:a    1
b    2
c    3
dtype: int64 In :s4 = Series(data=,index=['a','b','d'])
s4 Out:a    1
b    2
d    3
dtype: int64 In :s3 + s4 #NAN就是None
#在Series的运算中,只有索引一致的元素可以进行算数运算,否则补空 Out:a    2.0
b    4.0
c    NaN
d    NaN
dtype: float64  DataFrame(重要)¶

概述¶


[*]DataFrame是一个【表格型】的数据结构。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。

[*]行索引:index
[*]列索引:columns
[*]值:values

DataFrame的创建¶


[*]字典创建
 In :dic = {
    'name':['Tom','Jerry','Jay'],
    'age':,
    'salary':
}
table = DataFrame(data=dic)
table Out:  nameagesalary0Tom1020001Jerry2030002Jay304000  DataFrame的常用属性¶


[*]values,columns,index,shape
 In :table.shape #表格的形状 Out:(3, 3) In :table.values #返回表格所有的值 Out:array([['Tom', 10, 2000],
       ['Jerry', 20, 3000],
       ['Jay', 30, 4000]], dtype=object) In :table.index #行索引 Out:RangeIndex(start=0, stop=3, step=1) In :table.columns #列索引 Out:Index(['name', 'age', 'salary'], dtype='object')  索引操作(重点)¶


[*]对行进行索引
[*]队列进行索引
[*]对元素进行索引
 In :dic = {'names':['jay','tom','jerry'],
       'salary':,
      'age':}
df = DataFrame(data=dic,index=['a','b','c'])
df Out:  namessalaryageajay100030btom200040cjerry300050 In :#索引取单列:df
df['age'] Out:a    30
b    40
c    50
Name: age, dtype: int64 In :#索引取多列:df[]
df[['age','names']] Out:  agenamesa30jayb40tomc50jerry In :#索引取单行:df.loc/iloc
df.loc['a'] Out:names      jay
salary    1000
age         30
Name: a, dtype: object In :df.iloc #iloc后面跟的是隐式索引,loc后面跟显示索引 Out:names      jay
salary    1000
age         30
Name: a, dtype: object In :#索引取多行:df.loc/iloc[]
df.loc[['b','a']] Out:  namessalaryagebtom200040ajay100030 In :df Out:  namessalaryageajay100030btom200040cjerry300050 In :#索引取元素
df.loc['b','names'] #逗号左边是行,右边是列 Out:'tom'  切片操作¶


[*]批量切行
[*]批量切列
 In :#切行
df['a':'c'] Out:  namessalaryageajay100030btom200040cjerry300050 In :#切列
df.loc[:,'names':'salary'] Out:  namessalaryajay1000btom2000cjerry3000  数据查看¶


[*]查看DataFrame的概览和统计信息

[*]head()
[*]tail()
[*]info()
[*]describe()

 In :df.info() #查看表格的基本信息  <class 'pandas.core.frame.DataFrame'>
Index: 3 entries, a to c
Data columns (total 3 columns):
#   ColumnNon-Null CountDtype
----------------------------
0   names   3 non-null      object
1   salary3 non-null      int64
2   age   3 non-null      int64
dtypes: int64(2), object(1)
memory usage: 204.0+ bytes In :df.describe() #对数据表格进行统计描述 Out:  salaryagecount3.03.0mean2000.040.0std1000.010.0min1000.030.025%1500.035.050%2000.040.075%2500.045.0max3000.050.0  数据保存与加载¶

csv¶


[*]to_csv() & read_csv()
 In :#将df数据写入到文件中存储
dic = {'names':['jay','tom','jerry'],
       'salary':,
      'age':}
df = pd.DataFrame(data=dic,index=['a','b','c'])
df Out:  namessalaryageajay100030btom200040cjerry300050 In :df.to_csv('./df.csv') In :#读取外部文件 ./data/透视表-篮球赛.csv的数据到df表格中
ball = pd.read_csv('data/透视表-篮球赛.csv')
ball Out:  对手胜负主客场命中投篮数投篮命中率3分命中率篮板助攻得分0勇士胜客10230.4350.444611271国王胜客8210.3810.28639272小牛胜主10190.5260.46237293灰熊负主8200.4000.2505822476人胜客10200.5000.250313275黄蜂胜客8180.4440.4001011276灰熊负客6190.3160.2224820776人负主8210.3810.42947298尼克斯胜客9230.3910.35359319老鹰胜客8150.5330.5453112910爵士胜主19250.7600.8752135611骑士胜主8210.3810.42911133512灰熊胜主11250.4400.429483813步行者胜客9210.4290.2505152614猛龙负主8250.3200.2736113815太阳胜客12220.5450.545274816灰熊胜客9200.4500.500572917掘金胜主6160.3750.143892118尼克斯胜主12270.4440.3852103719篮网胜主13200.6500.6151083720步行者胜主8220.3640.3338102921湖人胜客13220.5910.444493622爵士胜客8190.4210.333532923开拓者胜客16290.5520.571834824鹈鹕胜主8160.5000.40011726  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 :#读取excel数据:data/运营商数据.xlsx
opt = pd.read_excel('data/运营商数据.xlsx')
opt Out:  用户号码用户套餐月租入网时间近6个月平均话费近6个月平均使用流量近6个月平均使用语音优惠名称号码品牌用户年龄用户性别是否订购是否参与活动活动开始时间活动结束时间外呼团队外呼时间外呼分钟数015620020209146.20509090.910500398.3167送3个月会员4G55男否NaNNaNNaNNaN2019119112502006042450.00003980.59276786.9000送3个月会员4G51男否NaNNaNNaNNaN2019092823502011120667.11251706.841767453.0833送3个月会员4G36女是会员赠送3个月201909.0202008.0团队D20190912834562012041299.00002872.30306741.3500送3个月会员4G35女是会员赠送3个月201909.0202008.0团队D2019099145882015050388.000028222.901100326.3500送3个月会员4G57男是会员赠送3个月201909.0202008.0团队D20190999......................................................1649316494492004101449.050050.79396757.2000送3个月会员4G23女是会员赠送3个月201910.0202009.0团队D20191084164941649592006031015.4250554.28600056.7667送3个月会员4G47女否NaNNaNNaNNaN20191101649516496282002041764.73500.002900111.8833送3个月会员2G61男否NaNNaNNaNNaN201910341649616497152012100118.1750186.96383321.8333送3个月会员2G28男否NaNNaNNaNNaN201910341649716498192017110336.22503839.240000149.6667送3个月会员4G37女是会员赠送3个月201910.0202009.0团队D2019106316498 rows × 17 columns
 In :opt.shape Out:(16498, 17) In :#写入数据到excel中
dic = {'names':['jay','tom','jerry'],
       'salary':,
      'age':}
df = pd.DataFrame(data=dic,index=['a','b','c'])
df Out:  namessalaryageajay100030btom200040cjerry300050 In :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 :dic = {'names':['jay','tom','jerry'],
       'salary':,
      'age':}
df = pd.DataFrame(data=dic)
df Out:  namessalaryage0jay1000301tom2000402jerry300050 In :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:3  

[*]读取数据库中的数据
 In :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:  idname0200技术1201人力资源2202销售3203运营  股票分析案例¶

 In :import pandas as pd
#可以将本地的文件数据读取到df,./data/600519.xlsx
df = pd.read_excel('data/600519.xlsx')
df.head() Out:  Unnamed: 0dateopenclosehighlowvolumecode002015-01-0524.09635.82337.38723.25094515.0600519112015-01-0633.53231.56035.86029.91455020.0600519222015-01-0729.93227.11433.07824.43254797.0600519332015-01-0828.07826.04128.55024.56940525.0600519442015-01-0924.80524.72329.68724.54153982.0600519 In :#删除无用的一列
df.drop(columns='Unnamed: 0',inplace=True) #inplace=True将删除操作作用在了原始数据中 In :df.shape Out:(2153, 7) In :df.head() Out:  dateopenclosehighlowvolumecode02015-01-0524.09635.82337.38723.25094515.060051912015-01-0633.53231.56035.86029.91455020.060051922015-01-0729.93227.11433.07824.43254797.060051932015-01-0828.07826.04128.55024.56940525.060051942015-01-0924.80524.72329.68724.54153982.0600519 In :df.info()  <class 'pandas.core.frame.DataFrame'>
RangeIndex: 2153 entries, 0 to 2152
Data columns (total 7 columns):
#   ColumnNon-Null CountDtype
----------------------------
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   volume2153 non-null   float64
6   code    2153 non-null   int64
dtypes: float64(5), int64(1), object(1)
memory usage: 117.9+ KB In :#将date列转转换成时间类型
df['date'] = df['date'].astype('datetime64') #astype用作类型转换 In :df.info()  <class 'pandas.core.frame.DataFrame'>
RangeIndex: 2153 entries, 0 to 2152
Data columns (total 7 columns):
#   ColumnNon-Null CountDtype         
----------------------------         
0   date    2153 non-null   datetime64
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   volume2153 non-null   float64      
6   code    2153 non-null   int64         
dtypes: datetime64(1), float64(5), int64(1)
memory usage: 117.9 KB In :#显示索引优势:可以增加数据的可读性
#将date列作为表格的行索引
df.set_index('date',inplace=True) In :df.head() Out:  openclosehighlowvolumecodedate      2015-01-0524.09635.82337.38723.25094515.06005192015-01-0633.53231.56035.86029.91455020.06005192015-01-0729.93227.11433.07824.43254797.06005192015-01-0828.07826.04128.55024.56940525.06005192015-01-0924.80524.72329.68724.54153982.0600519 In :df.shape Out:(2153, 6)  

[*]计算股票的每日收益率和7日波动率:通过计算收益率和波动率,我们可以评估股票的风险和收益情况。

[*]每日收益率:(当日收盘价 - 前一日的收盘价)/ 前一日的收盘价

[*]shift():将一组数据向前或者前后进行移动

[*]7日波动率:对每日收益率数据进行每7日滚动的方差计算

[*]rolling():设置滚动窗口


 In :df['close'].shift(1)#前日收盘 Out: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 :#每日收益率:(当日收盘价 - 前一日的收盘价)/ 前一日的收盘价
day_rate = (df['close'] - df['close'].shift(1)) / df['close'].shift(1)
day_rate Out: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 :#7日波动率
day_7_rolling_rate = day_rate.rolling(7).var() #var计算一组数据的方差
day_7_rolling_rate  Out: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 :#每日市值
day_values = df['close'] * df['volume']
day_values Out: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 :#找出市值数据中最大最小值下标(市值最大和最小日期)
day_values.idxmax() #求最大元素下标 Out:Timestamp('2021-09-27 00:00:00') In :day_values.idxmin() #求最小元素下标 Out:Timestamp('2015-02-02 00:00:00')  

[*]输出该股票所有收盘比开盘上涨3%以上的日期

[*](收盘 - 开盘) / 开盘 > 0.03

 In :ex = (df['close'] - df['open']) / df['open']> 0.03
ex #想获取所有True对应的索引 Out: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 :#在DataFrame中,可以使用布尔值作为表格的行索引:就会保留True对应的行数据,忽略False对应的行数据
df.loc #取出了True对应的行数据(满足要求的行数据) Out:  openclosehighlowvolumecodedate      2015-01-0524.09635.82337.38723.25094515.06005192015-01-1518.88720.86921.16917.60548585.06005192015-01-2011.73213.60515.8058.98761022.06005192015-01-2113.77817.49617.98712.80552674.06005192015-01-2315.46016.27818.33215.45033084.0600519.....................2022-11-151484.1791540.1791551.1491473.17956318.06005192023-01-051711.0891775.0891775.0891707.08947943.06005192023-02-201795.0891849.0891852.8891791.28929669.06005192023-05-221664.0991720.0891726.0891664.08941284.06005192023-07-281832.0001897.0001900.0001828.01039018.0600519252 rows × 6 columns
 In :df.loc.index #获取了满足要求行数据的行索引 Out: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', 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 :#找出每个月的第一个交易日的开盘价
monthly = df.resample('M').first() #取出了每个月第一个交易日对应的行数据
monthly.head(5)
#获取的数据会发现日期是每月最后一天的日期并不是第一个交易日的日期?(无需解决,自身存在的bug),但是行数据是没错 Out:  openclosehighlowvolumecodedate      2015-01-3124.09635.82337.38723.25094515.06005192015-02-2811.26910.64112.0789.44133983.06005192015-03-3125.16925.10527.89623.53231098.06005192015-04-3029.92329.29631.31428.51476875.06005192015-05-3181.40583.50587.16979.00554739.0600519 In :#买入股票的总花费
total_cost = monthly['open'].sum() * 100
total_cost Out:10173374.9  

[*]卖出股票到手多少钱?
 In :yearly = df.resample('A').last() #A表示年
yearly Out:  openclosehighlowvolumecodedate      2015-12-3173.91073.88075.19073.51019673.06005192016-12-31188.471196.011197.151188.47134687.06005192017-12-31586.648566.138595.148560.24876038.06005192018-12-31442.947469.657476.047439.64763678.06005192019-12-311077.1861077.1861082.1861070.69622588.06005192020-12-311852.2111909.2111910.1911850.21138860.06005192021-12-312000.5041980.5042003.4841958.50429665.06005192022-12-311710.0891701.0891727.0791701.08925333.06005192023-12-311790.1101794.1101799.0001783.00012800.0600519 In :recv = yearly['close'].sum() * 1200
recv Out:11721343.2 In :#计算总收益
recv - total_cost Out:1547968.2999999989  数据清洗¶

概述¶

数据清洗是指对原始数据进行处理和转换,以去除无效、重复、缺失或错误的数据,使数据符合分析的要求。
作用和意义¶


[*]提高数据质量:

[*]通过数据清洗,数据质量得到提升,减少错误分析和错误决策。

[*]增加数据可用性:

[*]清洗后的数据更加规整和易于使用,提高数据的可用性和可读性。

清洗维度¶


[*]缺失值处理:

[*]对于缺失的数据,可以删除包含缺失值的行或列或者填充缺失值。

[*]重复值处理:

[*]识别和删除重复的数据行,避免重复数据对分析结果产生误导。

[*]异常值处理:

[*]检测和处理异常值,决定是删除、替换或保留异常值。

缺失值清洗¶

缺失值/空值的删除¶


[*]伪造缺失值数据
 In :import pandas as pd
from pandas import DataFrame,Series

df = pd.read_csv('./data/none.csv',index_col=0)
df #NAN就是None空白 Out:  01234022644.0NaN111988820.085.01621983NaN84.0463936476.0NaN85476320.021.0455361936.0NaN82653987.089.01  

[*]缺失值的检测和删除,相关方法:

[*]isnull():检测df中的每一个元素是否为空值,为空则给该元素返回True,否则返回False
[*]notnull():检测df中的每一个元素是否为非空值,为非空则给该元素返回True,否则返回False
[*]any():检测一行或一列布尔值中是否存在一个或多个True,有则返回True,否则返回False
[*]all():检测一行或一列布尔值中是否存全部为True,有则返回True,否则返回False
[*]dropna():将存在缺失值/空值的行或者列进行删除

 In :#检测哪些列中存在空值
df.isnull() Out:  012340FalseFalseFalseTrueFalse1FalseFalseFalseFalseFalse2FalseFalseTrueFalseFalse3FalseFalseFalseTrueFalse4FalseFalseFalseFalseFalse5FalseFalseFalseTrueFalse6FalseFalseFalseFalseFalse In :df.notnull() Out:  012340TrueTrueTrueFalseTrue1TrueTrueTrueTrueTrue2TrueTrueFalseTrueTrue3TrueTrueTrueFalseTrue4TrueTrueTrueTrueTrue5TrueTrueTrueFalseTrue6TrueTrueTrueTrueTrue In :#可以判定哪些列中存在空值
df.isnull().any(axis=0)
#axis=0表示针对列进行any操作
#axis=1表示针对行进行any操作 Out:0    False
1    False
2   True
3   True
4    False
dtype: bool In :df.notnull().all(axis=0) Out:0   True
1   True
2    False
3    False
4   True
dtype: bool  

[*]dropna()进行空值检测和过滤
 In :df.dropna() #直接返回删除空值对应行后的结果,不会直接改变原始数据 Out:  012341988820.085.016476320.021.045653987.089.01  

[*]计算df中每一列存在缺失值的个数和占比
 In :for col in df.columns:
    #满足该条件则表示第col列中是存在空值
    if df.isnull().sum() > 0:
      #求出了该列空值的个数
      null_count = df.isnull().sum()
      #求出该列中空值的占比:空值的数量/列的总元素个数
      p = format(null_count / df.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 :df.fillna(value=666) Out:  01234022644.0666.0111988820.085.01621983666.084.0463936476.0666.085476320.021.0455361936.0666.082653987.089.01  

[*]使用近邻值填充空值
 In :df.fillna(axis=0,method='ffill').fillna(axis=0,method='bfill') #bfill
#在竖直方向上,会用空前面的值填充空值 Out:  01234022644.085.0111988820.085.0162198320.084.0463936476.084.085476320.021.0455361936.021.082653987.089.01  

[*]使用相关的统计值填充空值
 In :#可以使用空值列的均值、中位数等统计指标对空值进行填充
for col in df.columns:
    if df.isnull().sum() > 0:
      #计算出空值列对应的均值
      mean_value = df.mean()
      df.fillna(value=mean_value,inplace=True) In :df Out:  01234022644.00000069.75111988820.00000085.00162198333.83333384.00463936476.00000069.7585476320.00000021.00455361936.00000069.7582653987.00000089.001  注意:实现空值的清洗最好选择删除的方式,如果删除的成本比较高,再选择填充的方式。
  重复值清洗¶


[*]伪造重复行的数据源
 In :df = pd.read_csv('data/repeat.csv',index_col=0)
df Out:  01234076820149517085377286279692245300000456462514495000006662898141700000  

[*]使用duplicated()方法检测重复的行数据
 In :df.duplicated().sum() Out:2  

[*]使用drop_duplicates()方法检测且删除重复的行数据
 In :df.drop_duplicates() Out:  01234076820149517085377286279692245300000456462514496662898141  异常值清洗¶

异常值是分析师和数据科学家常用的术语,因为它需要密切注意,否则可能导致错误的估计。 简单来说,异常值是一个观察值,远远超出了样本中的整体模式。
异常值在统计学上的全称是疑似异常值,也称作离群点,异常值的分析也称作离群点分析。异常值是指样本中出现的“极端值”,数据值看起来异常大或异常小,其分布明显偏离其余的观测值。异常值分析是检验数据中是否存在不合常理的数据。

[*]给定条件的异常数据处理

[*]自定义一个1000行3列(A,B,C)取值范围为0-1的数据源,然后将C列中的值大于其两倍标准差的异常值进行清洗

 In :data = pd.read_csv('./data/outlier.csv',index_col=0)
data Out:  ABC00.7945140.3379130.29929010.5962590.5129300.55436920.1150030.4014900.66957330.7730070.5472630.78085740.4692550.3169570.214900............9950.6501190.0425320.4051129960.7042710.3171550.7797649970.1382250.4936250.1522159980.2731300.7638460.0312429990.5366710.6748450.0042241000 rows × 3 columns
 In :#C列的2倍标准差
twice_std = data['C'].std() * 2
twice_std Out:0.5705417437083701 In :#判定异常值
ex = data['C'] > twice_std
ex #True表示为异常值,False表示正常值 Out: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 :data.loc #取出了True对应的行数据(异常值对应的行数据) Out:  ABC20.1150030.4014900.66957330.7730070.5472630.78085770.0132300.4195070.96072880.8580910.8059640.586865100.1588100.0955860.775476............9810.8036460.7915880.7828599890.5342870.7349840.7013729910.2589870.0398010.7514509930.0029570.9399430.6732079960.7042710.3171550.779764424 rows × 3 columns
 In :drop_indexs = data.loc.index #提取了异常值对应行数据的行索引
drop_indexs Out: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 :#将异常值对应的行从数据表格中进行删除
data.drop(index=drop_indexs) Out:  ABC00.7945140.3379130.29929010.5962590.5129300.55436940.4692550.3169570.21490050.5393570.1074760.18749560.3855990.5619300.377683............9940.4942480.5581010.1285419950.6501190.0425320.4051129970.1382250.4936250.1522159980.2731300.7638460.0312429990.5366710.6748450.004224576 rows × 3 columns
  map映射¶


[*]映射就是指给一组数据中的每一个元素绑定一个固定的数据
 In :df = pd.read_csv('./data/map.csv').drop(columns='Unnamed: 0')
df Out:  namesalary0张三100001李四150002王五210003张三10000 In :#给每个人起一个英文名,将其作为表格中新的一列存在
dic = {
    '张三':'Tom',
    '李四':'Jerry',
    '王五':'Jay'
}#映射关系表
df['ename'] = df['name'].map(dic)
df Out:  namesalaryename0张三10000Tom1李四15000Jerry2王五21000Jay3张三10000Tom  map充当运算工具¶

 In :#将每一个人的税后薪资进行计算:超过5000部分的钱需要缴纳25%的税
def after_sal(s): #参数s就依次表示每一个人的薪资数据
    return s - (s-5000)*0.25
df['after_sal'] = df['salary'].map(after_sal)
df Out:  namesalaryenameafter_sal0张三10000Tom8750.01李四15000Jerry12500.02王五21000Jay17000.03张三10000Tom8750.0  排序¶

 In :data = pd.read_csv('./data/outlier.csv',index_col=0)
data.head() Out:  ABC00.7945140.3379130.29929010.5962590.5129300.55436920.1150030.4014900.66957330.7730070.5472630.78085740.4692550.3169570.214900 In :data.sort_values(by='C') #默认根据C列中的元素从小到大进行排序 Out:  ABC6470.1028260.2688950.0000365210.4915870.7670860.0006805990.5603230.8849600.001386170.4753330.9688090.0026397170.5610990.5967510.002810............9130.5759180.1552750.995703910.9144150.7389600.9965642730.7467500.4704660.996640670.8032910.9596920.9967803290.7283170.8106220.9985171000 rows × 3 columns
 In :data.sort_values(by='C',ascending=False)#从大到小排序 Out:  ABC3290.7283170.8106220.998517670.8032910.9596920.9967802730.7467500.4704660.996640910.9144150.7389600.9965649130.5759180.1552750.995703............7170.5610990.5967510.002810170.4753330.9688090.0026395990.5603230.8849600.0013865210.4915870.7670860.0006806470.1028260.2688950.0000361000 rows × 3 columns
 In :#axis=0表示的行,axis=1表示的是列
data.sort_index(axis=1,ascending=False) Out:  CBA00.2992900.3379130.79451410.5543690.5129300.59625920.6695730.4014900.11500330.7808570.5472630.77300740.2149000.3169570.469255............9950.4051120.0425320.6501199960.7797640.3171550.7042719970.1522150.4936250.1382259980.0312420.7638460.2731309990.0042240.6748450.5366711000 rows × 3 columns
 In :#手动对列索引进行排列,此处indices表示排列的结果(只能用隐式索引)
#axis=0表示的行,axis=1表示的是列
data.take(indices=,axis=1) Out:  BAC00.3379130.7945140.29929010.5129300.5962590.55436920.4014900.1150030.66957330.5472630.7730070.78085740.3169570.4692550.214900............9950.0425320.6501190.4051129960.3171550.7042710.7797649970.4936250.1382250.1522159980.7638460.2731300.0312429990.6748450.5366710.0042241000 rows × 3 columns
  map运算¶

 In :#计算下面表格中每个人的税后薪资:超过3000部分的钱缴纳50%的税,计算每个人的税后薪资
#加载数据
df = pd.read_csv('./data/fruits.csv').drop(columns='Unnamed: 0')
df Out:  itempricecolorweight0Apple4.0red121Banana3.0yellow202Orange3.0yellow503Banana2.5green304Orange4.0green205Apple2.0green44  分组聚合¶

  

[*]数据分类处理的核心:

[*]groupby()函数
[*]groups属性查看分组情况

 In :#加载数据
df = pd.read_csv('./data/fruits.csv').drop(columns='Unnamed: 0')
df Out:  itempricecolorweight0Apple4.0red121Banana3.0yellow202Orange3.0yellow503Banana2.5green304Orange4.0green205Apple2.0green44 In :#想根据不同水果种类对数据进行分组
df.groupby(by='item').groups #使用groupby分组后,调用groups查看分组的结果 Out:{'Apple': , 'Banana': , 'Orange': } In :#计算不同水果的平均价格
df.groupby(by='item')['price'] #单独取出每组数据的价格数据
mean_price = df.groupby(by='item')['price'].mean()
mean_price Out:item
Apple   3.00
Banana    2.75
Orange    3.50
Name: price, dtype: float64 In :mean_price.to_dict() Out:{'Apple': 3.0, 'Banana': 2.75, 'Orange': 3.5} In :#将每种水果的平均价格汇总到原始表格中
dic = {
    'Apple':3.00,
    'Banana':2.75,
    'Orange':3.50
}
#dic = mean_price.to_dict()

df['mean_price'] = df['item'].map(dic)
df Out:  itempricecolorweightmean_price0Apple4.0red123.001Banana3.0yellow202.752Orange3.0yellow503.503Banana2.5green302.754Orange4.0green203.505Apple2.0green443.00 In :#计算不同颜色水果的最大重量
color_max_weight = df.groupby(by='color')['weight'].max()
color_max_weight Out:color
green   44
red       12
yellow    50
Name: weight, dtype: int64 In :df['max_weight'] = df['color'].map(color_max_weight.to_dict())
df Out:  itempricecolorweightmean_pricemax_weight0Apple4.0red123.00121Banana3.0yellow202.75502Orange3.0yellow503.50503Banana2.5green302.75444Orange4.0green203.50445Apple2.0green443.0044  

[*]对分组后的结果进行多种不同形式的聚合操作
 In :#求每种水果的平均价格和最高价格、最低价格
df.groupby(by='item')['price'].agg(['mean','max','min']) Out:  meanmaxminitem   Apple3.004.02.0Banana2.753.02.5Orange3.504.03.0  透视表¶

透视表是一种可以对数据动态排布并且分类汇总的表格格式。或许大多数人都在Excel使用过数据透视表,也体会到它的强大功能,而在pandas中它被称作pivot_table。
 In :df = pd.read_csv('./data/透视表-篮球赛.csv')
df.head(3) Out:  对手胜负主客场命中投篮数投篮命中率3分命中率篮板助攻得分0勇士胜客10230.4350.444611271国王胜客8210.3810.28639272小牛胜主10190.5260.4623729 In :#根据胜负字段进行数据的分组,然后对每组数据进行均值计算
df.pivot_table(index='对手',aggfunc='mean') Out:  3分命中率助攻命中得分投篮命中率投篮数篮板对手       76人0.3395010.009.028.000.440520.53.5勇士0.4440011.0010.027.000.435023.06.0国王0.286009.008.027.000.381021.03.0太阳0.545007.0012.048.000.545022.02.0小牛0.462007.0010.029.000.526019.03.0尼克斯0.369009.5010.534.000.417525.03.5开拓者0.571003.0016.048.000.552029.08.0掘金0.143009.006.021.000.375016.08.0步行者0.2915012.508.527.500.396521.56.5湖人0.444009.0013.036.000.591022.04.0灰熊0.350257.758.527.250.401521.04.5爵士0.604008.0013.542.500.590522.03.5猛龙0.2730011.008.038.000.320025.06.0篮网0.615008.0013.037.000.650020.010.0老鹰0.5450011.008.029.000.533015.03.0骑士0.4290013.008.035.000.381021.011.0鹈鹕0.4000017.008.026.000.500016.01.0黄蜂0.4000011.008.027.000.444018.010.0 In :#根据胜负字段进行数据的分组,对分组中的篮板和得分两个字段进行求和运算
df.pivot_table(index='胜负',values=['篮板','得分'],aggfunc='sum') Out:  得分篮板胜负  胜692108负10919 In :#根据主客场字段进行数据分类后,对分类后的得分字段求最大值、篮板字段求均值和助攻字段求累加和操作
df.pivot_table(index='主客场',aggfunc={'得分':'max','篮板':'mean','助攻':'sum'}) Out:  助攻得分篮板主客场   主121565.333333客116484.846154 In :#获取所有队主客场的总得分
df.pivot_table(index='主客场',values='得分',aggfunc='sum') Out:  得分主客场 主397客404 In :#查看主客场下的总得分都是哪些具体球队的得分构成的
df.pivot_table(index='主客场',values='得分',aggfunc='sum',columns='对手') Out: 对手76人勇士国王太阳小牛尼克斯开拓者掘金步行者湖人灰熊爵士猛龙篮网老鹰骑士鹈鹕黄蜂主客场                  主29.0NaNNaNNaN29.037.0NaN21.029.0NaN60.056.038.037.0NaN35.026.0NaN客27.027.027.048.0NaN31.048.0NaN26.036.049.029.0NaNNaN29.0NaNNaN27.0 In :#查看主客场下的总得分都是哪些具体球队的得分构成的
df.pivot_table(index='主客场',values='得分',aggfunc='sum',columns='对手',fill_value=0) Out: 对手76人勇士国王太阳小牛尼克斯开拓者掘金步行者湖人灰熊爵士猛龙篮网老鹰骑士鹈鹕黄蜂主客场                  主29000293702129060563837035260客272727480314802636492900290027 In :#多条件分类汇总操作
df.pivot_table(index=['主客场','对手'],values='得分',aggfunc='sum') Out:   得分主客场对手 主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 :#加载数据
import pandas as pd
data = pd.read_excel('./data/Phone.xlsx') In :#缺失值处理 In :#查看不同品牌手机的累计销量和累计销售额,且对累计销量进行降序 In :#查看不同月份的销量情况,哪些月份销量比较高 In :#不同年龄段的购买力 In :#查看不同城市的购买力情况 In :#查看不同品牌的不同型号的最高和最低价格是多少  美国大选政治现金分析:
<ul>加载数据
查看数据的基本信息
指定数据截取,将如下字段的数据进行提取,其他数据舍弃

[*]cand_nm :候选人姓名
[*]contbr_nm : 捐赠人姓名
[*]contbr_st :捐赠人所在州
[*]contbr_employer : 捐赠人所在公司
[*]contbr_occupation : 捐赠人职业
[*]contb_receipt_amt :捐赠数额(美元)
[*]contb_receipt_dt : 捐款的日期
对新数据进行总览,查看是否存在缺失数据
用统计学指标快速描述数值型属性的概要。
空值处理。可能因为忘记填写或者保密等等原因,相关字段出现了空值,将其填充为NOT PROVIDE
异常值处理。将捐款金额
页: [1]
查看完整版本: day01:pandas数据分析