【从零开始学python数据分析与挖掘 刘顺祥著】

所用的资源连接,不需要花钱下载
or

文章目录

  • pandas
    • 序列与数据库的构造
      • 构建序列
      • 构造数据框
    • 外部数据的读取
      • 文本文件的读取
      • 电子表格的读取
      • 数据库数据的读取
    • 数据类型转换及描述统计
    • 字符与日期数据的处理
    • 常用的数据清洗方法
      • 重复观测处理
      • 缺失值处理
      • 异常值处理
    • 数据子集的获取
    • 透视表功能
    • 表之间的合并与连接
    • 分组聚合
    • 总结

pandas

序列与数据库的构造

构建序列

构造一个序列可以使用四种方式实现:

  1. 通过同质列表或元组构建。
  2. 通过字典构建。
  3. 通过Numpy中的一维数组构建。
  4. 通过数据框DataFrame中的某一列构建。
import numpy as np
import pandas as pd# 列表
s1 = pd.Series([2.8, 3.01, 8.99, 8.59, 5.18])
# 元组
s11 = pd.Series((2.8, 3.01, 8.99, 8.59, 5.18))
# 字典
s2 = pd.Series({'北京': 2.8, '上海': 3.01, '广东': 8.99, '江苏': 8.59, '浙江': 5.18})
# numpy的一维数组
s3 = pd.Series(np.arange(5))
# DataFrame中的某一列
df2 = pd.DataFrame({'姓名': ['张三', '李四', '王五'], '年龄': [23, 27, 26], '性别': ['男', '女', '男']})
s4 = pd.Series(df2['姓名'])

结果:

0    2.80
1    3.01
2    8.99
3    8.59
4    5.18
dtype: float64
******************************
北京    2.80
上海    3.01
广东    8.99
江苏    8.59
浙江    5.18
dtype: float64
******************************

不管是列表、元组还是一维数组,构造的序列结果都是第一个打印的样式。该样式会产生两列,第一列属于序列的行索引(可以理解为行号),自动从0开始,第二列才是序列的实际值

通过字典构造的序列就是第二个打印样式,仍然包含两列,所不同的是第一列不再是行号,而是具体的行名称(label),对应到字典中的键,第二列是序列的实际 值,对应到字典中的值

选取序列中的元素

# 取出序列的元素
print(s1[[0,3,4]])
print(s2[['北京','江苏']])
print(s2[[0, 3]])
# 通过numpy数学函数
print(np.log(s1))
print(np.mean(s1))
# 通过序列的方法
print(s1.mean())

如果序列是行名称风格,既可以使用位置(行号)索引,又 可以使用标签(行名称)索引

如果需要对序列进行数学函数的运算,一般首选numpy模块,因为Pandas模块在这方面比较缺乏;

如果是对序列做统计运算既可以使用numpy模块中的函数,也可以使用序列的“方法”,作者一般首选序列的“方法”,因为序列的“方法”更加丰富,如计算序列的偏度、峰度等,而Numpy是没有这样的函数的。

构造数据框

数据框实质上就是一个数据集,数据集的行代表每一条观测,数据集的列则代表各个变量。在一个数据框中可以存放不同数据类型的序列,如整数型、浮点型、字符型和日期时间型,而数组和序列则没有这样的优势,因为它们只能存放同质数据。构造一个数据框可以应用如下方式:

  1. 通过嵌套的列表或元组构造。
  2. 通过字典构造。
  3. 通过二维数组构造。
  4. 通过外部数据的读取构造。
# 列表
df1 = pd.DataFrame([['张三',23,'男'],['李四',27,'女'],['王五',26,'女']v])
# 字典
df2 = pd.DataFrame({'姓名':['张三','李四','王五'],'年龄':[23,27,26],'性别':['男','女','男']})
# numpy二维数组
df3 = pd.DataFrame(np.array([['张三',23,'男'],['李四',27,'女'],['王五',26,'女']]))

结果:

    0   1  2
0  张三  23  男
1  李四  27  女
2  王五  26  女
******************************姓名  年龄 性别
0  张三  23  男
1  李四  27  女
2  王五  26  男

选取数据框的元素

df2 = pd.DataFrame({'姓名': ['张三', '李四', '王五'], '年龄': [23, 27, 26], '性别': ['男', '女', '男']})print(df2)
# 方法一:df[columns list],输入列名
print(df2[['年龄', '性别']])
# 方法二:df.loc[],用label(行名或列名)做索引
print(df2.loc[1:3, ['年龄', '性别']])  # 选择[1,3)行的年龄和性别属性列
# 方法三:df.iloc[],行或列的整数位置
print(df2.iloc[1:3,1:3])

外部数据的读取

文本文件的读取

txt文件:

数据来源:某公司人事记录表
时间范围:2017.1.1~2017.6.30year,month,day,gender,occupation,income
1990,3,7,男,销售经理,6&000
1989,8,10,女,化妆师,8&500
# 1991,10,10,男,后端开发,13&500
1992,10,7,女,前端设计,6&500
1985,6,15,男,数据分析师,18&000该数据集仅用作参考!
不可以用于他用!
备注于2018年2月。

所呈现的txt格式数据集存在一些常见的问题,具体如下:

  1. 数据集并不是从第一行开始,前面几行实际上是数据集的来源说明,读取数据时需要
    注意什么问题。
  2. 数据集的末尾3行仍然不是需要读入的数据,如何避免后3行数据的读入。
  3. 中间部分的数据,第四行前加了#号,表示不需要读取该行,该如何处理
  4. 数据集中的收入一列,千分位符是&,如何将该字段读入为正常的数值型数据
  5. 如果需要将year、month和day三个字段解析为新的birthday字段,该如何做到。
  6. 数据集中含有中文,一般在读取含中文的文本文件时都会出现编码错误,该如何解决。
import numpy as np
import pandas as pduser_income = pd.read_table(filepath_or_buffer=r'./data_test01.txt',sep=',',parse_dates={'birthday': [0, 1, 2]},skiprows=3,skipfooter=4,comment='#',encoding='utf-8',thousands='&',engine='python')
print(user_income)

结果:

    birthday gender occupation  income
0 1990-03-07      男       销售经理    6000
1 1989-08-10      女        化妆师    8500
2 1992-10-07      女       前端设计    6500
3 1985-06-15      男      数据分析师   18000

代码分析:

  1. 由于read_table函数在读取数据时,默认将字段分隔符sep设置为Tab制表符,而原始数据集是用逗号分割每一列,所以需要改变sep参数;
  2. parse_dates参数通过字典实现前三列的日期解析,并合并为新字段birthday;
  3. skiprowsskipfooter参数分别实现原数据集开头几行和末尾几行数据的跳过;
  4. 由于数据部分的第四行前面加了#号,因此通过comment参数指定跳过的特殊行;
  5. 这里仅改变字符编码参数encoding是不够的,还需要将原始的txt文件另存为UTF-8格式;
  6. 对于收入一列,由于千分位符为&,因此为了保证数值型数据的正常读入,需要设置thousands参数为&。

电子表格的读取

该数据集反映的是儿童类服装的产品信息。在读取数据时需要注意两点:

一是该表没有表头,如何读数据的同时就设置好具体的表头;

另一点是数据集的第一列实际上是字符型的字段,如何避免数据读入时自动变成数值型字段。

00101 儿童裤 黑色 109
01123 儿童上衣 红色 229
01010 儿童鞋 蓝色 199
00100 儿童内衣 灰色 159
info = pd.read_excel(io='./data_test02.xlsx',names=['编号', '类型', '颜色', '价格'],converters={0: str}
)print(info)
      编号    类型  颜色   价格
0  01123  儿童上衣  红色  229
1  01010   儿童鞋  蓝色  199
2  00100  儿童内衣  灰色  159

这里需要重点说明的是converters参数,通过该参数可以指定某些变量需要转换的函数。 很显然,原始数据集中的商品ID是字符型的,如果不将该参数设置为{0:str},读入的数据与原始的数据集就不一致了。

数据库数据的读取

mysql为例,安装pip install pymysql

pymysql中的connect

简单使用

import pymysql# 连接Mysql数据库
conn = pymysql.connect(host='localhost',port=3306,database='fanle',user='root',password='root',# 如果报错'NoneType' object has no attribute 'encoding',则将utf-8修改为utf8charset='utf8'
)# 读取数据
user = pd.read_sql('select * from user;',conn)# 数据输出
print(user)# 关闭连接
conn.close()

由于MySQL的原数据集中含有中文,为了避免乱码的现象,将connect函数中的chartset参数设置为utf8

读取数据时,需要用到Pandas模块中的read_sql函数,该函数至少传入两个参数,一个是读取数据的查询语句(sql),另一个是连接桥梁(con)

在读取完数据之后,请务必关闭连接conn,因为它会一直占用电脑的资源,影响电脑的运行效率。

数据类型转换及描述统计

读入二手车信息:

import numpy as np
import pandas as pd# 读取数据
cars = pd.read_csv(filepath_or_buffer='./sec_cars.csv', sep=',')
# 预览数据的前5行
print(cars.head())
# 预览数据的后5行
print(cars.tail())
# 查看数据集的行列数
print(cars.shape)
# 查看数据集每个变量的数据类型
print(cars.dtypes)

结果:

  Brand                        Name  ... Sec_price  New_price
0    众泰    众泰T600 2016款 1.5T 手动 豪华型  ...       6.8      9.42万
1    众泰    众泰Z700 2016款 1.8T 手动 典雅型  ...       8.8     11.92万
2    众泰      大迈X5 2015款 1.5T 手动 豪华型  ...       5.8      8.56万
3    众泰  众泰T600 2017款 1.5T 手动 精英贺岁版  ...       6.2      8.66万
4    众泰    众泰T600 2016款 1.5T 手动 旗舰型  ...       7.0     11.59万[5 rows x 7 columns]Brand                              Name  ... Sec_price  New_price
11120    DS          DS 3 2012款 1.6L 手自一体 风尚版  ...     10.80     23.86万
11121    DS          DS 3 2012款 1.6L 手自一体 风尚版  ...      9.50     23.86万
11122    DS  DS 5LS 2015款 1.6T 手自一体 THP160雅致版  ...     12.30     20.28万
11123    DS   DS 5 2015款 1.8T 手自一体 THP200 豪华版  ...     17.99     28.65万
11124    DS         DS 6 2016款 1.6T 豪华版THP160  ...     16.00     24.95万[5 rows x 7 columns]
(11125, 7)
Brand             object
Name              object
Boarding_time     object
Km(W)            float64
Discharge         object
Sec_price        float64
New_price         object
dtype: object

结果如上,该数据集一共包含了11125条记录和7个变量,除二手车价格Sec_price和行驶里程数Km(W)为浮点型数据之外,其他变量均为字符型变量。

但是,从表5-5来看,二手车的上牌时间Boarding_time应该为日期型新车价格New_price应该为浮点型,为了后面的数据分析,需要对这两个变量进行类型的转换,具体操作如下:

原文中:

# 修改二手车上牌时间的数据类型
cars.Boarding_time = pd.to_datetime(cars.Boarding_time, format='%Y年%m月')
# 修改二手车新车价格的数据类型
cars.New_price = cars.New_price.str[:-1].astype('float')
# 重新查看各变量的数据类型
print(cars.dtypes)

但是数据集中有一些行的New_price列与其他不一样:

按照上述方法会报错:类型转换错误could not convert string to float: '暂'

故需要对这些行特殊处理,将其选出来后从数据框中删掉。

# 修改二手车上牌时间的数据类型
cars.Boarding_time = pd.to_datetime(cars.Boarding_time, format='%Y年%m月')
# 修改二手车新车价格的数据类型
cars.drop(cars[cars.New_price == '暂无'].index, inplace=True)
cars.New_price = cars.New_price.str[:-1].astype('float')
# 重新查看各变量的数据类型
print(cars.dtypes)

解析:

**cars.New_price == ‘暂无’:**每一行的布尔值

**cars[cars.New_price == ‘暂无’]:**返回为true的那些行。

**cars[cars.New_price == ‘暂无’].index:**返回那些行的下标。

结果:

Brand                    object
Name                     object
Boarding_time    datetime64[ns]
Km(W)                   float64
Discharge                object
Sec_price               float64
New_price               float64
dtype: object

如上结果所示,经过两行代码的处理,上牌时间Boarding_time更改为了日期型数据,新车价格New_price更改为了浮点型数据

Pandas模块中的to_datetime函数可以通过format参数灵活地将各种格式的字符型日期转换成真正的日期数据;

由于二手车新车价格含有“万”字,因此不能直接转换数据类型,为达到目的,需要三步走,首先通过str方法将该字段转换成字符串,然后通过切片手段,将“万”字剔除,最后运用astype方法,实现数据类型的转换。

  • 数值型变量的描述性统计

关于数据的描述性分析可以使用describe方法

# 数值型变量的描述性统计
print(cars.describe())

结果:

              Km(W)     Sec_price     New_price
count  10984.000000  10984.000000  10984.000000
mean       6.266357     25.652192     51.326006
std        3.480678     52.770268     79.682066
min        0.020000      0.650000      2.910000
25%        4.000000      5.200000     16.050000
50%        6.000000     10.200000     26.690000
75%        8.200000     23.800000     52.210000
max       34.600000    808.000000    976.920000

以上都是有关数据的统计描述,但并不能清晰地知道数据的形状分布,如数据是否有偏以及是否属于“尖峰厚尾”的特征,为了一次性统计数值型变量的偏度和峰度,可以参考如下代码:

# 选出所有数值型变量
num_val = cars.columns[cars.dtypes != 'object'][1:]
# print(cars[num_val])
# 计算偏度和峰度
def skew_kurt(x):skewness = x.skew()kurtsis = x.kurt()return pd.Series(data=[skewness, kurtsis], index=['Skew', 'Kurt'])
print(cars[num_val].apply(func=skew_kurt, axis=0))

结果:

         Km(W)  Sec_price  New_price
Skew  0.829915   6.313738   4.996912
Kurt  2.406258  55.381915  33.519911

如上结果所示正是每个数值型变量的偏度峰度,这三个变量都属于右偏(因为偏度值均大于0),而且三个变量也是尖峰的(因为峰度值也都大于0)

代码说明:columns方法用于返回数据集的所有变量名,通过布尔索引切片方法获得所有的数值型变量;

在自定义函数中,运用到了计算偏度的skew方法和计算峰度的kurt方法,然后将计算结果组合到序列中;

最后使用apply方法,该方法的目的就是对指定轴(axis=0,即垂直方向的各列)进行统计运算(运算函数
即自定义函数)。

  • 离散型变量的统计描述
# 离散型变量的统计描述
print(cars.describe(include=['object']))

结果:

        Brand                            Name Discharge
count   10984                       10984     10984
unique   104                        4374        33
top      别克  经典全顺 2010款 柴油 短轴 多功能 中顶 6座        国4
freq     1346                         126      4262

如上结果包含离散变量的四个统计值,分别是非缺失观测数唯一水平数频次最高的离散值具体的频次

如果要统计各个离散值的频次(以标准排量Discharge为例)

# 各个排量的频次统计
freq = cars.Discharge.value_counts()
print(freq)
# 各个排量的频次除以总数
freq_ratio = freq / cars.shape[0]
freq_df = pd.DataFrame({'freq': freq, 'freq_ratio': freq_ratio})
print(freq_df.head())

结果:

       freq  freq_ratio
国4     4262    0.388019
欧4     1848    0.168245
欧5     1131    0.102968
国4,国5   843    0.076748
国3      772    0.070284

如果需要把行标签设置为数据框中的列,可以使用reset_index方法,具体操作如下:

reset_index方法的使用还是比较频繁的,它可以非常方便地将行标签转换为数据框的变量

# 将行索引设为变量
freq_df.reset_index(inplace=True)
print(freq_df.head())

结果:

   index  freq  freq_ratio
0     国4  4262    0.388019
1     欧4  1848    0.168245
2     欧5  1131    0.102968
3  国4,国5   843    0.076748
4     国3   772    0.070284

字符与日期数据的处理

待处理的数据表:

需要做的修改:

  • 更改出生日期birthday和手机号tel两个字段的数据类型。
  • 根据出生日期birthday和开始工作日期start_work两个字段新增年龄和工龄两个字
    段。
  • 将手机号tel的中间四位隐藏起来。
  • 根据邮箱信息新增邮箱域名字段。
  • 如何基于other字段取出每个人员的专业信息。
import pandas as pd
import datetimedf = pd.read_excel(io='./data_test03.xlsx'
)# print(df.dtypes)
# print('*' * 30)
# 1.1更改birthday的数据类型
df.birthday = pd.to_datetime(df.birthday, format='%Y/%m/%d')
# 1.2更改tel的数据类型
df.tel = df.tel.astype('str')# 2.新增年龄和工龄两列
df['age'] = datetime.datetime.today().year - df.birthday.dt.year
df['workage'] = datetime.datetime.today().year - df.start_work.dt.year# 3.将手机号中间四位隐藏起来
df.tel = df.tel.apply(func=lambda x: x.replace(x[3:7], '****'))# 4.取出邮箱的域名
df['email_domain'] = df.email.apply(func=lambda x: x.split('@')[1])# 5.取出人员的专业信息
df['profession'] = df.other.str.findall('专业:(.*?),')
# print(df.other.str.findall('专业:(.*?),'))# 6.取出birthday、start_work和other变量
df.drop(['birthday', 'start_work', 'other'], axis=1, inplace=True)print(df.dtypes)
print(df)

Series对象DataFrame的列数据提供了cat、dt、str三种属性接口(accessors),分别对应分类数据、日期时间数据和字符串数据,通过这几个接口可以快速实现特定的功能,非常快捷。

  • other变量中获取人员的专业信息,该问题的解决使用了字符串的正则表达式,不管是字符串“方法”还是字符串正则,在使用前都需要对变量使用一次str方法。由于findall返回的是列表值,因此衍生出的email_domain字段值都是列表类型。

结果:

0    [电子商务]
1      [汽修]
2      [数学]
3     [统计学]
4      [美术]
5      [化学]
6      [物理]
7     [政治学]
  • 如果需要删除数据集中的某些变量,可以使用数据框的drop方法。该方法接受的第一个参数,就是被删除的变量列表,尤其要注意的是,需要将axis参数设置为1,因为默认drop方法是用来删除数据框中的行记录

常用的数据清洗方法

在数据处理过程中,一般都需要进行数据的清洗工作,如数据集是否存在重复、是否存在缺失、数据是否具有完整性和一致性、数据中是否存在异常值等。当发现数据中存在如上可能的问题时,都需要有针对性地处理。

重复观测处理

重复观测,顾名思义是指观测行存在重复的现象,重复观测的存在会影响数据分析和挖掘结果的准确性,所以在数据分析和建模之前需要进行观测的重复性检验,如果存在重复观测,还需要进行重复项的删除。

待处理数据集:

df = pd.read_excel(io='./data_test04.xlsx'
)print(df.duplicated())0    False
1    False
2    False
3     True
4    False
5    False
6    False
7    False
8     True
9     True

duplicated方法返回的是数据集每一行的检验结果,即10行数据会返回10个bool值。

为了能够得到最直接的结果,可以使用any函数。该函数表示的是在多个条件判断中,只要有一个条件为True,则any函数的结果就为True

print(any(df.duplicated()))

删除重复项:

df.drop_duplicates(inplace=True)

结果:

        appcategory appname  comments  install     love     size       update
0  网上购物-商城-团购-优惠-快递    每日优鲜      1297   204.7万   89.00%  15.16MB  2017年10月11日
1           网上购物-商城    苏宁易购       577  7996.8万   73.00%   58.9MB  2017年09月21日
2        网上购物-商城-优惠     唯品会      2543  7090.1万   86.00%  41.43MB  2017年10月13日
4           网上购物-商城     拼多多      1921  3841.9万   95.00%  13.35MB  2017年10月11日
5        网上购物-商城-优惠   寺库奢侈品      1964   175.4万  100.00%  17.21MB  2017年09月30日
6           网上购物-商城      淘宝     14244     4.6亿   68.00%  73.78MB  2017年10月13日
7     网上购物-商城-团购-优惠      当当       134  1615.3万   61.00%  37.01MB  2017年10月17日

完整代码:

df = pd.read_excel(io='./data_test04.xlsx'
)
print(any(df.duplicated()))
df.drop_duplicates(inplace=True)
print(df)

缺失值处理

缺失值是指数据集中的某些观测存在遗漏的指标值,缺失值的存在同样会影响到数据分析和挖掘的结果。

一般而言,当遇到缺失值(Python中用NaN表示)时,可以采用三种方法处置,分别是删除法替换法插补法

删除法是指当缺失的观测比例非常低时(如5%以内),直接删除存在缺失的观测,或者当某些变量的缺失比例非常高时(如85%以上),直接删除这些缺失的变量

替换法是指用某种常数直接替换那些缺失值,例如,对连续变量而言,可以使用均值或中位数替换,对于离散变量,可以使用众数替换;

插补法是指根据其他非缺失的变量或观测来预测缺失值,常见的插补法有回归插补法、K近邻插补法、拉格朗日插补法等。

待处理数据集:

判断数据集是否存在缺失值:

print(df.isnull())uid  regit_date  gender    age  income
0  False       False   False  False   False
1  False       False   False  False   False
2  False       False   False   True   False
3  False       False   False  False   False
4  False       False    True   True   False
5  False       False   False  False    True
6  False       False   False  False   False
7  False       False   False   True   False
8  False       False   False  False   False
9  False       False   False  False    True
  • 删除法

    • 删除记录(行)

    所有含缺失值的行记录全部删除

    df.dropna(inplace=True)
    
            uid regit_date gender   age   income
    0  81200457 2016-10-30      M  23.0   6500.0
    1  81201135 2016-11-08      M  27.0  10300.0
    3  84639281 2017-04-17      M  26.0   6000.0
    6  63881943 2015-10-07      M  21.0  10000.0
    8  77638351 2016-07-12      M  25.0  18000.0
    
    • 删除变量(列)
    df.drop('age',axis=1,inplace=True)
    
            uid regit_date gender   income
    0  81200457 2016-10-30      M   6500.0
    1  81201135 2016-11-08      M  10300.0
    2  80043782 2016-10-13      F  13500.0
    3  84639281 2017-04-17      M   6000.0
    4  73499801 2016-03-21    NaN   4500.0
    5  72399510 2016-01-18      M      NaN
    6  63881943 2015-10-07      M  10000.0
    7  35442690 2015-04-10      F   5800.0
    8  77638351 2016-07-12      M  18000.0
    9  85200189 2017-05-18      M      NaN
    
  • 替换法

    缺失值的替换需要借助于fillna方法,该方法中的method参数可以接受'ffill''bfill'两种值,分别代表前向填充后向填充

    缺失值的前向填充或后向填充一般适用于时间序列型的数据集,因为这样的数据前后具有连贯性,而一般的独立性样本并不适用该方法。

    • 前向替换

    前向填充是指用缺失值的前一个值替换

    df.fillna(method='ffill',inplace=True)
    
    • 后向替换

    后向填充则表示用缺失值的后一个值替换

    df.fillna(method='bfill',inplace=True)
    
    • 常数替换

    有些情况是有用的,例如某人确实没有工作,故收入为0,但是该方法就是典型的“以点概面”,非常容易导致错误,例如结果中的性别莫名多出异样的0值。

    df.fillna(value=0,inplace=True)
    
    • 统计值替换

    采用了更加灵活的替换方法,即**分别对各缺失变量使用不同的替换值**(需要采用字典的方式传递给value参数),性别使用众数替换,年龄使用均值替换,收入使用中位数替换

    df.fillna(value={'gender':df.gender.mode()[0],'age':df.age.mean(),'income':df.income.median()
    },inplace=True)
    

异常值处理

异常值是指那些远离正常值的观测,即“不合群”观测。

对于异常值的检测,一般采用两种方法,一种是n个标准差法另一种是箱线图判别法

标准差法判别公式:outlinear>∣x‾±nσ∣outlinear > |\overline{x} \pm n\sigma|outlinear>∣x±nσ∣,其中x‾\overline{x}x为样本均值,σ\sigmaσ为样本标准差。

n=2时,满足条件的观测就是异常值,当n=3时,满足条件的观测就是极端异常值

箱线图判别公式:outlinear>Q3+nIQRoutlinear > Q3 + nIQRoutlinear>Q3+nIQR 或者 outlinear<Q1−nIQRoutlinear < Q1 - nIQRoutlinear<Q1−nIQR,其中Q1为下四分位数(25%),Q3为上四位数(75%),IQR为四分位差(上四分位数与下四分位数的差)。

n=1.5时,满足条件的观测为异常值,当n=3时,满足条件的观测即为极端异常值

两种方法的选择标准:

如果数据近似服从正态分布时,优先选择n个标准差法,因为数据的分布相对比较对称;否则优先选择箱线图法,因为分位数并不会受到极端值的影响。

当数据存在异常时,一般可以使用删除法将异常值删除(前提是异常观测的比例不能太大)、替换法(可以考虑使用低于判别上限的最大值或高于判别下限的最小值替换、使用均值或中位数替换等)。

注意:counts是sunspots的一列,不是dataframe的属性。

sunspots = pd.read_csv(filepath_or_buffer='./sunspots.csv'
)# 标准差法
xbar = sunspots.counts.mean()
xstd = sunspots.counts.std()
print(f'标准差法异常值上限检测:{any(sunspots.counts > xbar + 2 * xstd)}')
print(f'标准差法异常值下限检测:{any(sunspots.counts < xbar - 2 * xstd)}')# 箱线图法
Q1 = sunspots.counts.quantile(q=0.25)
Q3 = sunspots.counts.quantile(q=0.75)
IQR = Q3-Q1
print(f'箱线图法异常值上限检测:{any(sunspots.counts > Q3 + 1.5 % IQR)}')
print(f'箱线图法异常值上限检测:{any(sunspots.counts < Q1 - 1.5 % IQR)}')
标准差法异常值上限检测:True
标准差法异常值下限检测:False
箱线图法异常值上限检测:True
箱线图法异常值上限检测:True

如上结果所示,不管是标准差检验法还是箱线图检验法,都发现太阳黑子数据中存在异常值,而且异常值都是超过上限临界值的。接下来,通过绘制太阳黑子数量的直方图核密度曲线图,用于检验数据是否近似服从正态分布进而选择一个最终的异常值判别方法

import matplotlib.pyplot as plt
# 设置绘图风格
plt.style.use('ggplot')
# 绘制直方图
sunspots.counts.plot(kind='hist', bins=30,density=True,stacked=True)
# 绘制核密度图
sunspots.counts.plot(kind='kde')
plt.show()

不管是直方图还是核密度曲线,所呈现的数据分布形状都是有偏的,并且属于右偏。基于此,这里选择箱线图法来判定太阳黑子数据中的那些异常值。

这里就使用替换法处理异常值,即使用低于判别上限的最大值或高于判别下限的最小值替换,代码如下:

print(sunspots.counts.describe())
# 箱线图中的异常值判别上限
UL = Q3 + 1.5 * IQR
print(UL)# 从数据中找出低于判别上限的最大值
replace_value = sunspots.counts[sunspots.counts < UL].copy().max()
print(replace_value)# 查看异常值的个数
print(sunspots.counts[sunspots.counts > UL].describe().count)
# 替换超过判别上限的异常值
sunspots.counts[sunspots.counts > UL] = replace_value
print(sunspots.counts.describe())

数据子集的获取

在Pandas模块中实现数据框子集的获取可以使用iloc、loc和ix三种“方法”,它们的语法可以表示成[rows_select,cols_select]

  • iloc只能通过行号列号进行数据的筛选,可以将iloc中的“i”理解为“integer”,,该索引方式与数组的索引方式类似,都是从0开始,可以间隔取号,对于切片仍然无法取到上限。
  • loc要比iloc灵活一些,可以将loc中的“l”理解为“label”,即可以向[rows_select,cols_select]指定具体的行标签(行名称)和列标签(字段名),可以将rows_select指定为具体的筛选条件,在iloc中是无法做到的
df1 = pd.DataFrame({'name': ['张三', '李四', '网二', '丁一', '李武'],'gender': ['男', '女', '女', '女', '男'],'age': [23, 26, 22, 25, 27]
}, columns=['name', 'gender', 'age'])
print(df1)
# 取出所有女性并且返回姓名和年龄
print(df1.iloc[1:4,[0,2]])
print(df1.loc[1:3,['name','age']])
# 条件索引
index = df1.gender[df1.gender=='女'].index
print(df1.iloc[index,:])
  name gender  age
0   张三      男   23
1   李四      女   26
2   网二      女   22
3   丁一      女   25
4   李武      男   27name gender  age
1   李四      女   26
2   网二      女   22
3   丁一      女   25

假如数据集没有行号,而是具体的行名称。

df2 = df1.set_index('name')
print(df2)
# 取出数据集的中间三行
print(df2.iloc[1:4,:])
print(df2.loc[['李四','网二','丁一'],:])
     gender  age
name
张三        男   23
李四        女   26
网二        女   22
丁一        女   25
李武        男   27gender  age
name
李四        女   26
网二        女   22
丁一        女   25

对于iloc来说,不管什么形式的数据集都可以使用,始终表示行索引,即取哪些行下标的观测;

loc不能使用数值表示行标签了,因为此时数据集的行标签是姓名,所以需要写入中间三行对应的姓名

布尔索引:

# 取出所有男性的姓名和年龄
# iloc不允许使用条件筛选
print(df1.iloc[df1.gender == '男', [0, 2]])
print(df1.iloc[df1.gender[df1.gender == '男'].index, [0, 2]])
print(df1.loc[df1.gender == '男', ['name', 'age']])

透视表功能

Pandas模块提供实现透视表功能的pivot_table函数

  • 单个分组变量的均值统计
diamonds = pd.read_table(filepath_or_buffer=r'./diamonds.csv',sep=','
)
print(diamonds)
print(pd.pivot_table(data=diamonds, index='color', values='price', margins='总计', margins_name='总计'))
       carat        cut color clarity  depth  table  price     x     y     z
0       0.23      Ideal     E     SI2   61.5   55.0    326  3.95  3.98  2.43
1       0.21    Premium     E     SI1   59.8   61.0    326  3.89  3.84  2.31
2       0.23       Good     E     VS1   56.9   65.0    327  4.05  4.07  2.31
3       0.29    Premium     I     VS2   62.4   58.0    334  4.20  4.23  2.63
4       0.31       Good     J     SI2   63.3   58.0    335  4.34  4.35  2.75
...      ...        ...   ...     ...    ...    ...    ...   ...   ...   ...
53935   0.72      Ideal     D     SI1   60.8   57.0   2757  5.75  5.76  3.50
53936   0.72       Good     D     SI1   63.1   55.0   2757  5.69  5.75  3.61
53937   0.70  Very Good     D     SI1   62.8   60.0   2757  5.66  5.68  3.56
53938   0.86    Premium     H     SI2   61.0   58.0   2757  6.15  6.12  3.74
53939   0.75      Ideal     D     SI2   62.2   55.0   2757  5.83  5.87  3.64[53940 rows x 10 columns]price
color
D      3169.954096
E      3076.752475
F      3724.886397
G      3999.135671
H      4486.669196
I      5091.874954
J      5323.818020
总计     3932.799722
  • 两个分组变量的列联表
print(pd.pivot_table(data=diamonds,index='clarity',columns='cut',values='carat',aggfunc=np.size,margins=True,margins_name='总计'))
cut      Fair  Good  Ideal  Premium  Very Good     总计
clarity
I1        210    96    146      205         84    741
IF          9    71   1212      230        268   1790
SI1       408  1560   4282     3575       3240  13065
SI2       466  1081   2598     2949       2100   9194
VS1       170   648   3589     1989       1775   8171
VS2       261   978   5071     3357       2591  12258
VVS1       17   186   2047      616        789   3655
VVS2       69   286   2606      870       1235   5066
总计       1610  4906  21551    13791      12082  53940

对于列联表来说行和列都需要指定某个分组变量,所以index参数columns参数都需要指定一个分组变量,并且统计的不再是某个变量的均值,而是观测个数,所以aggfunc参数需要指定numpy模块中的size函数。

表之间的合并与连接

Pandas模块同样提供了关于多表之间的合并和连接操作函数,分别是concat函数merge函数,首先介绍一下这两个函数的用法和重要参数含义。

  1. 合并函数concat

针对合并函数concat,需要强调:

  • 如果纵向合并多个数据集,即使这些数据集都含有“姓名”变量,但变量名称不一致,如Name和name,通过合并后,将会得到错误的结果
  1. 连接函数merge

    该函数的最大缺点是,每次只能操作两张数据表的连接,如果有n张表需要连接,则必须经过n-1次的merge函数使用。

    # 构造数据集
    df3 = pd.DataFrame({'id': [1, 2, 3, 4, 5],'name': ['张三', '李四', '王二', '丁一', '赵五'],'age': [27, 24, 25, 23, 25],'gender': ['男', '男', '男', '女', '女']
    })
    df4 = pd.DataFrame({'Id': [1, 2, 2, 4, 4, 4, 5],'kemu': ['科目1', '科目1', '科目2', '科目1', '科目2', '科目3', '科目1'],'score': [83, 81, 87, 75, 86, 74, 88]
    })
    df5 = pd.DataFrame({'id': [1, 3, 5],'name': ['张三', '王二', '赵五'],'income': [13500, 18000, 15000]
    })
    # 三表的数据连接
    # 先连接df3和df4
    merge1 = pd.merge(left=df3,right=df4,left_on='id',right_on='Id',how='left')
    print(merge1)
    print('*'*50)
    # 再连接df5
    merge2 = pd.merge(left=merge1,right=df5,left_on='id',right_on='id',how='left')
    print(merge2)
    
       id name  age gender   Id kemu  score
    0   1   张三   27      男  1.0  科目1   83.0
    1   2   李四   24      男  2.0  科目1   81.0
    2   2   李四   24      男  2.0  科目2   87.0
    3   3   王二   25      男  NaN  NaN    NaN
    4   4   丁一   23      女  4.0  科目1   75.0
    5   4   丁一   23      女  4.0  科目2   86.0
    6   4   丁一   23      女  4.0  科目3   74.0
    7   5   赵五   25      女  5.0  科目1   88.0
    **************************************************id name_x  age gender   Id kemu  score name_y   income
    0   1     张三   27      男  1.0  科目1   83.0     张三  13500.0
    1   2     李四   24      男  2.0  科目1   81.0    NaN      NaN
    2   2     李四   24      男  2.0  科目2   87.0    NaN      NaN
    3   3     王二   25      男  NaN  NaN    NaN     王二  18000.0
    4   4     丁一   23      女  4.0  科目1   75.0    NaN      NaN
    5   4     丁一   23      女  4.0  科目2   86.0    NaN      NaN
    6   4     丁一   23      女  4.0  科目3   74.0    NaN      NaN
    7   5     赵五   25      女  5.0  科目1   88.0     赵五  15000.0
    

分组聚合

以珠宝数据为例,统计各颜色和刀工组合下的珠宝数量、最小重量、平均价格和最大面宽。如果读者对SQL比较熟悉的话,可以写成下方的SQL代码,实现数据的统计:

diamonds = pd.read_csv(filepath_or_buffer='./diamonds.csv', sep=',')
# print(diamonds)# 通过groupby方法,指定分组变量
grouped = diamonds.groupby(by=['color', 'cut'])
# 对分组变量进行统计汇总
res = grouped.aggregate({'color': np.size,'carat': np.min,'price': np.mean# 'face_width': np.max
})print(res)
print('*'*50)
# 数据集重命名
res.rename(columns={'color': 'counts','carat': 'min_weight','price': 'avg_price'
}, inplace=True)
print(res)
print('*'*50)
# 将行索引转换为数据框的变量
res.reset_index(inplace=True)
print(res)
                 color  carat        price
color cut
D     Fair         163   0.25  4291.061350Good         662   0.23  3405.382175Ideal       2834   0.20  2629.094566Premium     1603   0.20  3631.292576Very Good   1513   0.23  3470.467284
E     Fair         224   0.22  3682.312500Good         933   0.23  3423.644159Ideal       3903   0.20  2597.550090Premium     2337   0.20  3538.914420Very Good   2400   0.20  3214.652083
F     Fair         312   0.25  3827.003205Good         909   0.23  3495.750275Ideal       3826   0.23  3374.939362Premium     2331   0.20  4324.890176Very Good   2164   0.23  3778.820240
G     Fair         314   0.23  4239.254777Good         871   0.23  4123.482204Ideal       4884   0.23  3720.706388Premium     2924   0.23  4500.742134Very Good   2299   0.23  3872.753806
H     Fair         303   0.33  5135.683168Good         702   0.25  4276.254986Ideal       3115   0.23  3889.334831Premium     2360   0.23  5216.706780Very Good   1824   0.23  4535.390351
I     Fair         175   0.41  4685.445714Good         522   0.30  5078.532567Ideal       2093   0.23  4451.970377Premium     1428   0.23  5946.180672Very Good   1204   0.24  5255.879568
J     Fair         119   0.30  4975.655462Good         307   0.28  4574.172638Ideal        896   0.23  4918.186384Premium      808   0.30  6294.591584Very Good    678   0.24  5103.513274
**************************************************counts  min_weight    avg_price
color cut
D     Fair          163        0.25  4291.061350Good          662        0.23  3405.382175Ideal        2834        0.20  2629.094566Premium      1603        0.20  3631.292576Very Good    1513        0.23  3470.467284
E     Fair          224        0.22  3682.312500Good          933        0.23  3423.644159Ideal        3903        0.20  2597.550090Premium      2337        0.20  3538.914420Very Good    2400        0.20  3214.652083
F     Fair          312        0.25  3827.003205Good          909        0.23  3495.750275Ideal        3826        0.23  3374.939362Premium      2331        0.20  4324.890176Very Good    2164        0.23  3778.820240
G     Fair          314        0.23  4239.254777Good          871        0.23  4123.482204Ideal        4884        0.23  3720.706388Premium      2924        0.23  4500.742134Very Good    2299        0.23  3872.753806
H     Fair          303        0.33  5135.683168Good          702        0.25  4276.254986Ideal        3115        0.23  3889.334831Premium      2360        0.23  5216.706780Very Good    1824        0.23  4535.390351
I     Fair          175        0.41  4685.445714Good          522        0.30  5078.532567Ideal        2093        0.23  4451.970377Premium      1428        0.23  5946.180672Very Good    1204        0.24  5255.879568
J     Fair          119        0.30  4975.655462Good          307        0.28  4574.172638Ideal         896        0.23  4918.186384Premium       808        0.30  6294.591584Very Good     678        0.24  5103.513274
**************************************************color        cut  counts  min_weight    avg_price
0      D       Fair     163        0.25  4291.061350
1      D       Good     662        0.23  3405.382175
2      D      Ideal    2834        0.20  2629.094566
3      D    Premium    1603        0.20  3631.292576
4      D  Very Good    1513        0.23  3470.467284
5      E       Fair     224        0.22  3682.312500
6      E       Good     933        0.23  3423.644159
7      E      Ideal    3903        0.20  2597.550090
8      E    Premium    2337        0.20  3538.914420
9      E  Very Good    2400        0.20  3214.652083
10     F       Fair     312        0.25  3827.003205
11     F       Good     909        0.23  3495.750275
12     F      Ideal    3826        0.23  3374.939362
13     F    Premium    2331        0.20  4324.890176
14     F  Very Good    2164        0.23  3778.820240
15     G       Fair     314        0.23  4239.254777
16     G       Good     871        0.23  4123.482204
17     G      Ideal    4884        0.23  3720.706388
18     G    Premium    2924        0.23  4500.742134
19     G  Very Good    2299        0.23  3872.753806
20     H       Fair     303        0.33  5135.683168
21     H       Good     702        0.25  4276.254986
22     H      Ideal    3115        0.23  3889.334831
23     H    Premium    2360        0.23  5216.706780
24     H  Very Good    1824        0.23  4535.390351
25     I       Fair     175        0.41  4685.445714
26     I       Good     522        0.30  5078.532567
27     I      Ideal    2093        0.23  4451.970377
28     I    Premium    1428        0.23  5946.180672
29     I  Very Good    1204        0.24  5255.879568
30     J       Fair     119        0.30  4975.655462
31     J       Good     307        0.28  4574.172638
32     J      Ideal     896        0.23  4918.186384
33     J    Premium     808        0.30  6294.591584
34     J  Very Good     678        0.24  5103.513274

总结

Pandas读书笔记相关推荐

  1. python第三章上机实践_《机器学习Python实践》读书笔记-第三章

    <机器学习Python实践>,第三章,第一个机器学习项目 以往目录:橘猫吃不胖:<机器学习Python实践>读书笔记-第一章​zhuanlan.zhihu.com 书中介绍了一 ...

  2. 《Hands-On Machine Learning with Scikit-Learn TensorFlow》读书笔记(二):端到端的机器学习

    最近有时间看书了,把以前想看的书捡一下,翻译中顺便加上自己的理解,写个读书笔记. 假装最近聘请了一家房地产公司的数据科学家,然后通过一个示例项目,从头至尾了解机器学习. 以下是要完成的主要步骤: 查看 ...

  3. 吐血整理!万字原创读书笔记,数据分析的知识点全在这里了

    作者:JaneK 来源:大数据DT 导读:今天这篇文章是「大数据」内容合伙人JaneK关于<Python数据分析与数据化运营>的一篇读书笔记. 本文目录: Python数据分析与挖掘 01 ...

  4. Matplotlib 数据可视化(读书笔记)

    Python 数据科学手册第四章读书笔记,仅供学习交流使用 4. Matplotlib 数据可视化 4.1 Matplotlib 常用技巧 4.1.1 导入 Matplotlib plt 是最常用的接 ...

  5. 《数据分析方法论和业务实战》读书笔记

    <数据分析方法和业务实战>读书笔记 共9章:前两章入门,3-7章介绍基本方法,8章从项目实战介绍数据分析,9章答疑常见问题. 1 数据分析基础 数据分析的完整流程 数据->信息-〉了 ...

  6. zz[读书笔记]《Interpretable Machine Learning》

    [读书笔记]<Interpretable Machine Learning> Jul 19, 2019 看到这本书,特意翻了下微博妖僧老冯_之前的一条微博,这样写道:"在机器学习 ...

  7. 《Hands-On Machine Learning with Scikit-Learn TensorFlow》读书笔记(一):机器学习概述

    最近有时间看书了,把以前想看的书捡一下,翻译中顺便加上自己的理解,写个读书笔记. 一.什么是机器学习? Machine Learning is the science (and art) of pro ...

  8. [The Path to QUANT] 《Volatility Trading》by Euan Sinclair 读书笔记 Chapter 3

    <Volatility Trading> by Euan Sinclair Chapter 3 收益率和波动率的典型事实 典型事实列表 波动率并非常数 收益率分布 成交量和波动率 波动率分 ...

  9. Spyder 入门基础学习《谁说菜鸟不会数据分析》-方小敏著 读书笔记

    写在前面:本文作者购买了<谁说菜鸟不会数据分析>-方小敏著  这本书,感觉写的非常好,遂作为日常读书笔记进行了记录.推荐使用python进行数据分析的初学者购买此书学习. (文章中部分内容 ...

最新文章

  1. 有关EUV光刻机,你需要知道这些
  2. request和response一览
  3. .htaccess伪静态实例记录
  4. HBase 2.X版本的元数据修复及一种数据迁移方式
  5. 正能量之项目经理的自我修养
  6. 前端学习(2450):页面布局制作
  7. es 仅返回单个字段 查询_ES性能优化实战,几十亿数据查询 3 秒返回!
  8. Go 系列教程 —— 26. 结构体取代类
  9. Empty paragraph passed to @param command
  10. Navicat Premium 16 隆重登场
  11. 定宣讲初稿,筑宣讲之基
  12. python爬虫-爬妹子图
  13. 凝固永恒瞬间的艺术 纪实摄影到底怎么拍
  14. 如何消除SettingWithCopyWarning警告
  15. windows server 2003 AD迁移到windows server2012(一)
  16. Excel 数据导入SQL XML 自动生成表头
  17. SpringMvc同时配置jsp和html的视图解析器
  18. v24.03 鸿蒙内核源码分析(进程概念) | 如何更好的理解进程 | 百篇博客分析HarmonyOS源码
  19. Vite为啥如此之快
  20. Android项目文件结构

热门文章

  1. sql注入21-27关
  2. 程序员创业:小型软件公司如何做大
  3. slot/slot-scope is deprecated, consult docs for better alternative
  4. zip() 和zip(*)
  5. Excel排名函数PERCENTRANK计算逻辑
  6. 2020中兴硬件类笔试
  7. 速卖通选品分享:宠物用品韩国市场洞察
  8. 全网最全的微服务链路追踪实践-SkyWalking(看这一篇就够了)
  9. CRC-循环冗余检验(计网)
  10. CSS--BEM风格介绍