谁说菜鸟不会数据分析(python篇)

前言

实现 《谁说菜鸟不会数据分析》 代码

数据处理

数据清洗

数据排序

按照一定顺序排序,以便研究者通过浏览数据发现一些明显的特征、规律或趋势,找到解决问题的线索。有助于对数据检查纠错,以及为重新归类或分组等提供方便

1
import pandas as pd
1
2
data = pd.read_csv('../data/cnbook/第四章/4.2.1 数据排序/数据排序.csv')
data.head()
用户ID 性别 年龄
0 100000 52
1 100001 23
2 100002 30
3 100006 28
4 100010 28
1
2
3
4
5
# 根据年龄升序、性别降序
data.sort_values(
['年龄', '性别'],
ascending = [True, False]
)
用户ID 性别 年龄
6 100012 21
1 100001 23
7 100013 24
9 100016 26
5 100011 27
3 100006 28
4 100010 28
2 100002 30
10 100017 30
8 100015 33
0 100000 52

重复数据处理

重复数据查找
1
2
data = pd.read_csv('../data/cnbook/第四章/4.2.2 重复数据处理/重复值.csv')
data
ID 姓名 性别
0 1 刘一
1 1 刘一
2 3 张三
3 4 李四
4 5 王五
5 6 赵六
6 7 孙七
7 8 周八
8 9 吴九
9 10 郑十
1
2
# 查找行重复的
data.duplicated()
0    False
1     True
2    False
3    False
4    False
5    False
6    False
7    False
8    False
9    False
dtype: bool
1
2
# 根据 性别 列,找出重复的位置
data.duplicated(['性别'])
0    False
1     True
2     True
3    False
4     True
5     True
6     True
7     True
8     True
9     True
dtype: bool
重复数据删除
1
data.drop_duplicates()
ID 姓名 性别
0 1 刘一
2 3 张三
3 4 李四
4 5 王五
5 6 赵六
6 7 孙七
7 8 周八
8 9 吴九
9 10 郑十

缺失数据处理

处理方法:

  1. 填充,用平均值等方法进行填充
  2. 删除有缺失值的行,如果数据量较小不适合
  3. 不处理
数据补齐
1
2
data = pd.read_csv('../data/cnbook/第四章/4.2.3 缺失值处理/常见缺失值.csv')
data
ID 姓名 消费
0 1 刘一 256.0
1 2 陈二 NaN
2 3 张三 282.0
3 4 李四 245.0
4 5 王五 162.0
5 6 赵六 295.0
6 7 孙七 173.0
7 8 周八 197.0
8 9 吴九 236.0
9 10 郑十 311.0
1
2
# 使用平均值填充
data.fillna(data['消费'].mean())
ID 姓名 消费
0 1 刘一 256.000000
1 2 陈二 239.666667
2 3 张三 282.000000
3 4 李四 245.000000
4 5 王五 162.000000
5 6 赵六 295.000000
6 7 孙七 173.000000
7 8 周八 197.000000
8 9 吴九 236.000000
9 10 郑十 311.000000
删除缺失值
1
data.dropna()
ID 姓名 消费
0 1 刘一 256.0
2 3 张三 282.0
3 4 李四 245.0
4 5 王五 162.0
5 6 赵六 295.0
6 7 孙七 173.0
7 8 周八 197.0
8 9 吴九 236.0
9 10 郑十 311.0
空格数据处理

空格数据是指字符串型数据的前面或后面存在空格

1
2
data = pd.read_csv('../data/cnbook/第四章/4.2.4 空格值处理/空格值.csv')
data
id name
0 1 KEN
1 2 JIMI
2 3 John
1
data.name.str.strip()
0     KEN
1    JIMI
2    John
Name: name, dtype: object

数据转换

数值转字符串

1
2
data = pd.read_csv('../data/cnbook/第四章/4.3.1 数值转字符/数值转字符.csv')
data
ID 姓名 消费 电话号码
0 1 刘一 256.1 166547114238
1 2 陈二 239.5 166423353436
2 3 张三 282.6 166556915853
3 4 李四 245.8 166434728749
4 5 王五 162.3 166544742252
5 6 赵六 295.3 166827395761
6 7 孙七 173.6 166917847616
7 8 周八 197.9 166528757061
8 9 吴九 236.2 166809774605
9 10 郑十 311.1 166434676621
1
2
# 查看类型
data.dtypes
ID        int64
姓名       object
消费      float64
电话号码      int64
dtype: object
1
data['电话号码'].dtype
dtype('int64')
1
2
3
# 把 电话号码 列转换为字符型
data['电话号码'] = data['电话号码'].astype(str)
data['电话号码'].dtype
dtype('O')

字符串转数值

1
2
data['电话号码'] = data['电话号码'].astype(float)
data['电话号码'].dtype
dtype('float64')

字符串转时间

时间转换
1
2
data = pd.read_csv('../data/cnbook/第四章/4.3.3 字符转时间/字符转时间.csv')
data
电话 注册时间 是否微信
0 166412894295 2011/1/1
1 135416795207 2012/2/3
2 177423353436 2013/3/2
3 189424978309 2014/4/11
4 134450811715 2015/5/18
5 137450811771 2016/6/12
6 173450811789 2017/7/15
7 188450811792 2018/8/17
8 168450811840 2019/9/16
1
data['注册时间'].dtype
dtype('O')
1
2
3
4
5
data['时间'] = pd.to_datetime(
data.注册时间,
format='%Y/%m/%d'
)
data.head()
电话 注册时间 是否微信 时间
0 166412894295 2011/1/1 2011-01-01
1 135416795207 2012/2/3 2012-02-03
2 177423353436 2013/3/2 2013-03-02
3 189424978309 2014/4/11 2014-04-11
4 134450811715 2015/5/18 2015-05-18
1
data.时间.dtype
dtype('<M8[ns]')
时间格式化
1
2
data['年月'] = data.时间.dt.strftime('%Y-%m')
data.head()
电话 注册时间 是否微信 时间 年月
0 166412894295 2011/1/1 2011-01-01 2011-01
1 135416795207 2012/2/3 2012-02-03 2012-02
2 177423353436 2013/3/2 2013-03-02 2013-03
3 189424978309 2014/4/11 2014-04-11 2014-04
4 134450811715 2015/5/18 2015-05-18 2015-05

数据抽取

字段分拆

按照位置分拆
1
2
data = pd.read_csv('../data/cnbook/第四章/4.4.1 字段拆分/字段拆分.csv')
data
tel
0 18922254812
1 13522255003
2 13422259938
3 18822256753
4 18922253721
5 13422259313
6 13822254373
7 13322252452
8 18922257681
1
2
3
# 电话转换成字符串格式
data['tel'] = data['tel'].astype(str)
data.head()
tel
0 18922254812
1 13522255003
2 13422259938
3 18822256753
4 18922253721
1
2
3
4
5
6
7
# 运营商
data['bands'] = data['tel'].str.slice(0, 3)
# 地区
data['areas'] = data['tel'].str.slice(3, 7)
# 号码段
data['nums'] = data['tel'].str.slice(7, 11)
data.head()
tel bands areas nums
0 18922254812 189 2225 4812
1 13522255003 135 2225 5003
2 13422259938 134 2225 9938
3 18822256753 188 2225 6753
4 18922253721 189 2225 3721
按照分隔符拆分
1
2
data = pd.read_csv('../data/cnbook/第四章/4.4.1 字段拆分/分隔符.csv')
data
name
0 Apple iPad mini
1 华为 MediaPad 7Vogue
2 昂达(ONDA) V975四核
3 华为(HUAWEI) 荣耀X1
4 酷比魔方(CUBE) TALK7X四核
5 惠普(HP) Slate 7
6 酷比魔方(ACUBE) TALK97
7 三星(SAMSUNG) GALAXY NotePro
1
2
3
4
# 按照 空格 分割,从 第一个 开始,使用 数据框 返回结果
newData = data['name'].str.split(' ', 1, True)
newData.columns = ['band', 'name']
newData.head()
band name
0 Apple iPad mini
1 华为 MediaPad 7Vogue
2 昂达(ONDA) V975四核
3 华为(HUAWEI) 荣耀X1
4 酷比魔方(CUBE) TALK7X四核
时间属性抽取
1
2
data = pd.read_csv('../data/cnbook/第四章/4.4.1 字段拆分/时间属性.csv')
data.head()
电话 注册时间 是否微信
0 166412894295 2011/1/1 12:13:24
1 135416795207 2012/2/3 1:15:38
2 177423353436 2013/3/2 13:54:55
3 189424978309 2014/4/11 11:00:03
4 134450811715 2015/5/18 10:02:23
1
2
3
4
data['时间'] = pd.to_datetime(
data.注册时间,
format='%Y/%m/%d'
)
1
2
data['时间.年'] = data['时间'].dt.year
data.head()
电话 注册时间 是否微信 时间 时间.年
0 166412894295 2011/1/1 12:13:24 2011-01-01 12:13:24 2011
1 135416795207 2012/2/3 1:15:38 2012-02-03 01:15:38 2012
2 177423353436 2013/3/2 13:54:55 2013-03-02 13:54:55 2013
3 189424978309 2014/4/11 11:00:03 2014-04-11 11:00:03 2014
4 134450811715 2015/5/18 10:02:23 2015-05-18 10:02:23 2015

记录抽取

1
2
data = pd.read_csv('../data/cnbook/第四章/4.4.2 记录抽取/记录抽取.csv')
data.head()
id comments title ptime
0 1197453 10071 华为(HUAWEI) 荣耀平板 2015-05-26
1 1192330 16879 Apple iPad平板 2012-01-26
2 1225995 2218 小米(MI)7.9英寸平板 2013-06-16
3 1308557 12605 Apple IPad mini平板 2013-05-26
4 1185287 11836 微软(Microsoft) Surface Pro 3 2016-08-21

关键词抽取

1
2
fdata = data[data.title.str.contains('台电', na=False)]
fdata
id comments title ptime
7 1150612 5857 台电(Teclast) P98 2015-05-14
8 1285329 2482 台电(Teclast)X98 Air 2015-08-21

空值抽取

1
2
fdata = data[data.title.isnull()]
fdata
id comments title ptime
5 1197789 2084 NaN 2015-03-03

数值范围抽取

1
2
3
# 单条件比较运算
fdata = data[data['comments'] > 10000]
fdata
id comments title ptime
0 1197453 10071 华为(HUAWEI) 荣耀平板 2015-05-26
1 1192330 16879 Apple iPad平板 2012-01-26
3 1308557 12605 Apple IPad mini平板 2013-05-26
4 1185287 11836 微软(Microsoft) Surface Pro 3 2016-08-21
6 996957 11123 Apple iPad Air 2015-02-10
1
2
3
# 之间
fdata = data[data['comments'].between(1000, 10000)]
fdata
id comments title ptime
2 1225995 2218 小米(MI)7.9英寸平板 2013-06-16
5 1197789 2084 NaN 2015-03-03
7 1150612 5857 台电(Teclast) P98 2015-05-14
8 1285329 2482 台电(Teclast)X98 Air 2015-08-21

组合条件抽取

1
2
3
# 多条件
fdata = data[(data['comments'] > 1000) & (data['comments'] < 10000)]
fdata
id comments title ptime
2 1225995 2218 小米(MI)7.9英寸平板 2013-06-16
5 1197789 2084 NaN 2015-03-03
7 1150612 5857 台电(Teclast) P98 2015-05-14
8 1285329 2482 台电(Teclast)X98 Air 2015-08-21

时间范围抽取

1
data.ptime.dtype
dtype('O')
1
data.ptime = pd.to_datetime(data.ptime)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from datetime import datetime
# 定义时间
dt1 = datetime(
year = 2015,
month = 1,
day = 1
)
dt2 = datetime(
year = 2015,
month = 12,
day = 1
)
fdata = data[(data.ptime >= dt1) & (data.ptime <= dt2)]
fdata
id comments title ptime
0 1197453 10071 华为(HUAWEI) 荣耀平板 2015-05-26
5 1197789 2084 NaN 2015-03-03
6 996957 11123 Apple iPad Air 2015-02-10
7 1150612 5857 台电(Teclast) P98 2015-05-14
8 1285329 2482 台电(Teclast)X98 Air 2015-08-21

随机抽样

按个数抽样
1
2
data = pd.read_csv('../data/cnbook/第四章/4.4.3 随机抽样/随机抽样.csv')
data.head()
ID 姓名 消费
0 1 刘一 256
1 2 陈二 239
2 3 张三 282
3 4 李四 245
4 5 王五 162
1
2
sdata = data.sample(n=3)
sdata
ID 姓名 消费
0 1 刘一 256
6 7 孙七 173
1 2 陈二 239
按照百分比抽样
1
2
sdata = data.sample(frac=0.2)
sdata
ID 姓名 消费
2 3 张三 282
1 2 陈二 239
是否放回抽样
1
2
3
# replace=True 为放回抽样
sdata = data.sample(n=3, replace=True)
sdata
ID 姓名 消费
7 8 周八 197
4 5 王五 162
1 2 陈二 239

数据合并

记录合并

1
2
data1 = pd.read_csv('../data/cnbook/第四章/4.5.1 记录合并/台电.csv')
data1.head()
id comments title
0 1235465 3256 台电(Teclast)X98 Air Ⅱ
1 1312660 342 台电(Teclast)X10HD 3G
2 1192758 1725 台电(Teclast)P98 Air
3 1312671 279 台电(Teclast)X89
4 1094550 2563 台电(Teclast) P19HD
1
2
data2 = pd.read_csv('../data/cnbook/第四章/4.5.1 记录合并/小米.csv')
data2.head()
id comments title
0 1134006 13231 小米(MI) MIX
1 1192330 6879 小米(MI) MIX 2
2 1225995 2218 小米(MI) MAX
3 1225988 1336 小米(MI) MAX 2
4 1284247 578 小米(MI) 7
1
2
data3 = pd.read_csv('../data/cnbook/第四章/4.5.1 记录合并/苹果.csv')
data3.head()
id comments title
0 996961 62014 Apple iPad Air
1 996967 59503 Apple iPad mini
2 1246836 8791 Apple iPhone 7
3 996964 9332 Apple iPhone X
4 1250967 4932 Apple iPad Air 2
1
pd.concat([data1, data2, data3])
id comments title
0 1235465 3256 台电(Teclast)X98 Air Ⅱ
1 1312660 342 台电(Teclast)X10HD 3G
2 1192758 1725 台电(Teclast)P98 Air
3 1312671 279 台电(Teclast)X89
4 1094550 2563 台电(Teclast) P19HD
5 1327452 207 台电(Teclast)P80 3G
0 1134006 13231 小米(MI) MIX
1 1192330 6879 小米(MI) MIX 2
2 1225995 2218 小米(MI) MAX
3 1225988 1336 小米(MI) MAX 2
4 1284247 578 小米(MI) 7
0 996961 62014 Apple iPad Air
1 996967 59503 Apple iPad mini
2 1246836 8791 Apple iPhone 7
3 996964 9332 Apple iPhone X
4 1250967 4932 Apple iPad Air 2

字段合并

1
2
data = pd.read_csv('../data/cnbook/第四章/4.5.2 字段合并/字段合并.csv')
data.head()
band area num
0 189 2225 4812
1 135 2225 5003
2 134 2225 9938
3 188 2225 6753
4 189 2225 3721
1
2
3
4
5
# 用 + 号进行合并,因为如果是数值型的会进行计算,所以需要先转换成字符串型的
data = data.astype(str)
# 将 band、area、num 列合并为一个新的列
data['tel'] = data['band'] + data['area'] + data['num']
data.head()
band area num tel
0 189 2225 4812 18922254812
1 135 2225 5003 13522255003
2 134 2225 9938 13422259938
3 188 2225 6753 18822256753
4 189 2225 3721 18922253721

字段匹配

1
2
items = pd.read_csv('../data/cnbook/第四章/4.5.3 字段匹配/商品名称.csv')
items.head()
id comments title
0 996955 2412 Apple iPad Air
1 1251208 2061 Apple iPad Air 2
2 1197453 10071 华为(HUAWEI) 荣耀平板
3 1192330 6879 小米(MI) 平板
4 1225995 2218 小米(MI) MAX 2
1
2
prices = pd.read_csv('../data/cnbook/第四章/4.5.3 字段匹配/商品价格.csv')
prices.head()
id oldPrice nowPrice
0 996955 3099 4299
1 1251208 4288 4289
2 1197453 799 1000
3 1192330 1699 1799
4 1225995 1299 1599
1
2
3
4
5
6
7
# 内链接 inner
pd.merge(
items,
prices,
left_on='id',
right_on='id'
)
id comments title oldPrice nowPrice
0 996955 2412 Apple iPad Air 3099 4299
1 1251208 2061 Apple iPad Air 2 4288 4289
2 1197453 10071 华为(HUAWEI) 荣耀平板 799 1000
3 1192330 6879 小米(MI) 平板 1699 1799
4 1225995 2218 小米(MI) MAX 2 1299 1599
5 1308557 1605 华为(HUAWEI) Mate 2 999 1099
6 1185287 836 微软(Microsoft) Surface Pro 3 7388 7588
7 1197789 2084 小米(MI) MAX 1 1299 1500
8 996957 11123 Apple iPad Air 2 2788 2899
9 1150612 5857 台电(Teclast) P98 999 1499
1
2
3
4
5
6
7
8
# 左链接 left
pd.merge(
items,
prices,
left_on='id',
right_on='id',
how='left'
)
id comments title oldPrice nowPrice
0 996955 2412 Apple iPad Air 3099.0 4299
1 1251208 2061 Apple iPad Air 2 4288.0 4289
2 1197453 10071 华为(HUAWEI) 荣耀平板 799.0 1000
3 1192330 6879 小米(MI) 平板 1699.0 1799
4 1225995 2218 小米(MI) MAX 2 1299.0 1599
5 1308557 1605 华为(HUAWEI) Mate 2 999.0 1099
6 1185287 836 微软(Microsoft) Surface Pro 3 7388.0 7588
7 1197789 2084 小米(MI) MAX 1 1299.0 1500
8 996957 11123 Apple iPad Air 2 2788.0 2899
9 1150612 5857 台电(Teclast) P98 999.0 1499
10 0 0 左边才有的 NaN NaN
1
2
3
4
5
6
7
8
# 右链接 right
pd.merge(
items,
prices,
left_on='id',
right_on='id',
how='right'
)
id comments title oldPrice nowPrice
0 996955 2412.0 Apple iPad Air 3099 4299
1 1251208 2061.0 Apple iPad Air 2 4288 4289
2 1197453 10071.0 华为(HUAWEI) 荣耀平板 799 1000
3 1192330 6879.0 小米(MI) 平板 1699 1799
4 1225995 2218.0 小米(MI) MAX 2 1299 1599
5 1308557 1605.0 华为(HUAWEI) Mate 2 999 1099
6 1185287 836.0 微软(Microsoft) Surface Pro 3 7388 7588
7 1197789 2084.0 小米(MI) MAX 1 1299 1500
8 996957 11123.0 Apple iPad Air 2 2788 2899
9 1150612 5857.0 台电(Teclast) P98 999 1499
10 1 NaN NaN 1 右边才有的
1
2
3
4
5
6
7
8
# 外链接 outer
pd.merge(
items,
prices,
left_on='id',
right_on='id',
how='outer'
)
id comments title oldPrice nowPrice
0 996955 2412.0 Apple iPad Air 3099.0 4299
1 1251208 2061.0 Apple iPad Air 2 4288.0 4289
2 1197453 10071.0 华为(HUAWEI) 荣耀平板 799.0 1000
3 1192330 6879.0 小米(MI) 平板 1699.0 1799
4 1225995 2218.0 小米(MI) MAX 2 1299.0 1599
5 1308557 1605.0 华为(HUAWEI) Mate 2 999.0 1099
6 1185287 836.0 微软(Microsoft) Surface Pro 3 7388.0 7588
7 1197789 2084.0 小米(MI) MAX 1 1299.0 1500
8 996957 11123.0 Apple iPad Air 2 2788.0 2899
9 1150612 5857.0 台电(Teclast) P98 999.0 1499
10 0 0.0 左边才有的 NaN NaN
11 1 NaN NaN 1.0 右边才有的

数据计算

简单计算

1
2
data = pd.read_csv('../data/cnbook/第四章/4.6.1 简单计算/单价数量.csv')
data.head()
name price num
0 A 6058 408
1 B 1322 653
2 C 7403 400
3 D 4911 487
4 E 3320 56
1
2
data['total'] = data.price * data.num
data.head()
name price num total
0 A 6058 408 2471664
1 B 1322 653 863266
2 C 7403 400 2961200
3 D 4911 487 2391657
4 E 3320 56 185920

时间计算

1
2
data = pd.read_csv('../data/cnbook/第四章/4.6.2 时间计算/时间计算.csv')
data.head()
电话 注册时间 是否微信
0 166412894295 2011/1/1
1 135416795207 2012/2/3
2 177423353436 2013/3/2
3 189424978309 2014/4/11
4 134450811715 2015/5/18
1
2
3
4
5
data['时间'] = pd.to_datetime(
data.注册时间,
format='%Y/%m/%d'
)
data.head()
电话 注册时间 是否微信 时间
0 166412894295 2011/1/1 2011-01-01
1 135416795207 2012/2/3 2012-02-03
2 177423353436 2013/3/2 2013-03-02
3 189424978309 2014/4/11 2014-04-11
4 134450811715 2015/5/18 2015-05-18
1
2
3
4
from datetime import datetime
# 计算注册天数
data['注册天数'] = datetime.now() - data.时间
data.head()
电话 注册时间 是否微信 时间 注册天数
0 166412894295 2011/1/1 2011-01-01 3188 days 18:19:05.434942
1 135416795207 2012/2/3 2012-02-03 2790 days 18:19:05.434942
2 177423353436 2013/3/2 2013-03-02 2397 days 18:19:05.434942
3 189424978309 2014/4/11 2014-04-11 1992 days 18:19:05.434942
4 134450811715 2015/5/18 2015-05-18 1590 days 18:19:05.434942
1
2
data['注册天数'] = data['注册天数'].dt.days
data.head()
电话 注册时间 是否微信 时间 注册天数
0 166412894295 2011/1/1 2011-01-01 3188
1 135416795207 2012/2/3 2012-02-03 2790
2 177423353436 2013/3/2 2013-03-02 2397
3 189424978309 2014/4/11 2014-04-11 1992
4 134450811715 2015/5/18 2015-05-18 1590

数据标准化

数据标准化是指对数据按照比例进行缩放,使之落入特定区域,数据标准化的作用就是消除单位量纲的影响,方便进行不同变量间的对比分析

0-1标准化:
x’ = (x - min) / (max -min)

1
2
data = pd.read_csv('../data/cnbook/第四章/4.6.3 数据标准化/标准化.csv')
data.head()
ID 姓名 消费
0 1 刘一 256
1 2 陈二 239
2 3 张三 282
3 4 李四 245
4 5 王五 162
1
2
3
# 实现 0-1 标准化
data['消费标准化'] = (data['消费'] - data['消费'].min())/(data['消费'].max() - data['消费'].min())
data.head()
ID 姓名 消费 消费标准化
0 1 刘一 256 0.630872
1 2 陈二 239 0.516779
2 3 张三 282 0.805369
3 4 李四 245 0.557047
4 5 王五 162 0.000000

数据分组

1
2
data = pd.read_csv('../data/cnbook/第四章/4.6.4 数据分组/数据分组.csv')
data.head()
tel cost
0 166424556600 2.0
1 166424557199 5.0
2 166424561768 75.3
3 166424569696 20.0
4 166424569924 97.3
分组的数组
1
2
# 查看最大值最小值
data.cost.min()
2.0
1
data.cost.max()
100.0
1
2
3
4
# 定义分组
bins = [0, 20, 40, 60, 80, 100]
data['cut'] = pd.cut(data.cost, bins)
data.head()
tel cost cut
0 166424556600 2.0 (0, 20]
1 166424557199 5.0 (0, 20]
2 166424561768 75.3 (60, 80]
3 166424569696 20.0 (0, 20]
4 166424569924 97.3 (80, 100]
区间的闭合

默认是使用 左开右闭 的
right = True 表示 左开右闭
right = False 表示 左闭右开

1
2
3
bins = [0, 20, 40, 60, 80, 100, 120]
data['cut'] = pd.cut(data.cost, bins, right=False)
data.head()
tel cost cut
0 166424556600 2.0 [0, 20)
1 166424557199 5.0 [0, 20)
2 166424561768 75.3 [60, 80)
3 166424569696 20.0 [20, 40)
4 166424569924 97.3 [80, 100)
自定义标签
1
2
3
4
bins = [0, 20, 40, 60, 80, 100, 120]
customLabels = ['0-20', '20-40', '40-60', '60-80', '80-100', '100-120']
data['cut'] = pd.cut(data.cost, bins, right=False, labels=customLabels)
data.head()
tel cost cut
0 166424556600 2.0 0-20
1 166424557199 5.0 0-20
2 166424561768 75.3 60-80
3 166424569696 20.0 20-40
4 166424569924 97.3 80-100

数据分析

对比分析

概念,无案例

基本统计分析

描述性统计分析,主要包括数据的集中趋势分析、数据的离散程度分析、数据的频数分布分析等,常用的统计指标有:计数、求和、平均数、
方差、标准差等

1
2
data = pd.read_csv('../data/cnbook/第五章/5.2 基本统计分析/描述性统计分析.csv')
data
id area sales
0 1 越秀区 1250
1 2 天河区 1253
2 3 番禺区 1280
3 4 南沙区 1260
4 5 增城区 1310
5 6 花都区 1190
6 7 海珠区 1288
7 8 黄埔区 1310
8 9 白云区 1220
9 10 从化市 1380
10 11 萝岗区 1256
11 12 荔湾区 1220
1
2
# 描述性统计分析
data.sales.describe()
count      12.000000
mean     1268.083333
std        50.510950
min      1190.000000
25%      1242.500000
50%      1258.000000
75%      1293.500000
max      1380.000000
Name: sales, dtype: float64

获取百分位值

1
2
# 获取 30% 分位数最近的值
data.sales.quantile(0.3, interpolation='nearest')
1250

分组分析

1
2
data = pd.read_csv('../data/cnbook/第五章/5.3 分组分析/分组分析.csv')
data.head()
id reg_date id_num gender birthday age
0 100000 2011/1/1 15010219621116401I 1962/11/16 52
1 100001 2011/1/1 45092319910527539E 1991/5/27 23
2 100002 2011/1/1 35010319841017421J 1984/10/17 30
3 100006 2011/1/1 37110219860824751B 1986/8/24 28
4 100010 2011/1/1 53042219860714031J 1986/7/14 28
1
2
3
4
# 按照性别分组,对年龄求平均值
data.groupby(
by=['gender']
).age.agg('mean')
gender
女    30.392493
男    26.979629
Name: age, dtype: float64
1
2
3
4
5
# 分组不做索引
data.groupby(
by=['gender'],
as_index=False
).age.agg('mean')
gender age
0 30.392493
1 26.979629

结构分析

在分组的基础上,计算各组成部分所占的比重

1
2
data = pd.read_csv('../data/cnbook/第五章/5.4 结构分析/结构分析.csv')
data.head()
id reg_date id_num gender birthday age
0 100000 2011/1/1 15010219621116401I 1962/11/16 52
1 100001 2011/1/1 45092319910527539E 1991/5/27 23
2 100002 2011/1/1 35010319841017421J 1984/10/17 30
3 100006 2011/1/1 37110219860824751B 1986/8/24 28
4 100010 2011/1/1 53042219860714031J 1986/7/14 28
1
2
3
4
ga = data.groupby(
by='gender'
).id.agg('count')
ga
gender
女     4316
男    54785
Name: id, dtype: int64
1
2
# 计算各分组的比例
ga/ga.sum()
gender
女    0.073028
男    0.926972
Name: id, dtype: float64

分布分析

1
2
data = pd.read_csv('../data/cnbook/第五章/5.5 分布分析/分布分析.csv')
data.head()
用户ID 注册日期 身份证号码 性别 出生日期 年龄
0 100000 2011/1/1 15010219621116401I 1962/11/16 52
1 100001 2011/1/1 45092319910527539E 1991/5/27 23
2 100002 2011/1/1 35010319841017421J 1984/10/17 30
3 100006 2011/1/1 37110219860824751B 1986/8/24 28
4 100010 2011/1/1 53042219860714031J 1986/7/14 28
1
2
3
4
5
6
7
# 根据年龄段分组
bins = [0, 20, 30, 40, 100]
data['年龄分层'] = pd.cut(
data.年龄,
bins
)
data.head()
用户ID 注册日期 身份证号码 性别 出生日期 年龄 年龄分层
0 100000 2011/1/1 15010219621116401I 1962/11/16 52 (40, 100]
1 100001 2011/1/1 45092319910527539E 1991/5/27 23 (20, 30]
2 100002 2011/1/1 35010319841017421J 1984/10/17 30 (20, 30]
3 100006 2011/1/1 37110219860824751B 1986/8/24 28 (20, 30]
4 100010 2011/1/1 53042219860714031J 1986/7/14 28 (20, 30]
1
2
3
4
aggResult = data.groupby(
by='年龄分层',
).用户ID.agg('count')
aggResult
年龄分层
(0, 20]       2061
(20, 30]     46858
(30, 40]      8729
(40, 100]     1453
Name: 用户ID, dtype: int64
1
2
3
# 计算各分组百分比
temp = round(aggResult/aggResult.sum(), 4)*100
temp.map('{:,.2f}%'.format)
年龄分层
(0, 20]       3.49%
(20, 30]     79.28%
(30, 40]     14.77%
(40, 100]     2.46%
Name: 用户ID, dtype: object

交叉分析

pandas 实现透视表功能

1
2
3
4
5
6
pandas.DataFrame.pivot_table(values, index, columns, aggfunc='mean', fill_value=None)
values: 透视表中的值
index: 透视表中的行
columns: 透视表中的列
aggfuc: 统计函数
fill_value: NA 值统一的替换值

1
2
data = pd.read_csv('../data/cnbook/第五章/5.6 交叉分析/交叉分析.csv')
data.head()
用户ID 注册日期 身份证号码 性别 出生日期 年龄
0 100000 2011/1/1 15010219621116401I 1962/11/16 52
1 100001 2011/1/1 45092319910527539E 1991/5/27 23
2 100002 2011/1/1 35010319841017421J 1984/10/17 30
3 100006 2011/1/1 37110219860824751B 1986/8/24 28
4 100010 2011/1/1 53042219860714031J 1986/7/14 28
1
2
3
bins = [0, 20, 30, 40, 100]
data['年龄分层'] = pd.cut(data.年龄, bins)
data.head()
用户ID 注册日期 身份证号码 性别 出生日期 年龄 年龄分层
0 100000 2011/1/1 15010219621116401I 1962/11/16 52 (40, 100]
1 100001 2011/1/1 45092319910527539E 1991/5/27 23 (20, 30]
2 100002 2011/1/1 35010319841017421J 1984/10/17 30 (20, 30]
3 100006 2011/1/1 37110219860824751B 1986/8/24 28 (20, 30]
4 100010 2011/1/1 53042219860714031J 1986/7/14 28 (20, 30]
1
2
3
4
5
6
7
# 进行交叉分析
data.pivot_table(
values='用户ID',
index='年龄分层',
columns='性别',
aggfunc='count'
)
性别
年龄分层
(0, 20] 111 1950
(20, 30] 2903 43955
(30, 40] 735 7994
(40, 100] 567 886

RFM 分析

1
2
data = pd.read_csv('../data/cnbook/第五章/5.7 RFM分析/RFM分析.csv')
data.head()
OrderID CustomerID DealDateTime Sales
0 4529 34858 2014-05-14 807
1 4532 14597 2014-05-14 160
2 4533 24598 2014-05-14 418
3 4534 14600 2014-05-14 401
4 4535 24798 2014-05-14 234
1
2
data['DealDateTime'] = pd.to_datetime(data.DealDateTime, format='%Y/%m/%d')
data.DealDateTime.dtype
dtype('<M8[ns]')
1
2
3
4
# 计算时间差
data['DateDiff'] = datetime.now() - data['DealDateTime']
data['DateDiff'] = data['DateDiff'].dt.days
data.head()
OrderID CustomerID DealDateTime Sales DateDiff
0 4529 34858 2014-05-14 807 1959
1 4532 14597 2014-05-14 160 1959
2 4533 24598 2014-05-14 418 1959
3 4534 14600 2014-05-14 401 1959
4 4535 24798 2014-05-14 234 1959
1
2
3
4
5
6
# 计算最近时间距离
R_Agg = data.groupby(
by='CustomerID',
as_index=False
).DateDiff.agg('min')
R_Agg.head()
CustomerID DateDiff
0 14568 1468
1 14569 1558
2 14570 1488
3 14571 1528
4 14572 1552
1
2
3
4
5
6
# 计算频率
F_Agg = data.groupby(
by='CustomerID',
as_index=False
).OrderID.agg('count')
F_Agg.head()
CustomerID OrderID
0 14568 15
1 14569 12
2 14570 15
3 14571 15
4 14572 8
1
2
3
4
5
6
# 计算金额
M_Agg = data.groupby(
by='CustomerID',
as_index=False
).Sales.agg('sum')
M_Agg.head()
CustomerID Sales
0 14568 6255
1 14569 5420
2 14570 8261
3 14571 8124
4 14572 3334
1
2
3
4
# 合并数据
aggData = R_Agg.merge(F_Agg).merge(M_Agg)
aggData.columns = ['CustomerID', 'RecencyAgg', 'FrequencyAgg', 'MonetaryAgg']
aggData.head()
CustomerID RecencyAgg FrequencyAgg MonetaryAgg
0 14568 1468 15 6255
1 14569 1558 12 5420
2 14570 1488 15 8261
3 14571 1528 15 8124
4 14572 1552 8 3334
1
2
3
4
5
6
7
8
# 对 R、F、M 三个统计量进行得分计算
# 按照大小顺序分成五组
# 1. 获取分割点,指定分组的百分位点,获取百分位点的值
bins = aggData.RecencyAgg.quantile(
q=[0, 0.2, 0.4, 0.6, 0.8, 1],
interpolation='nearest'
)
bins
0.0    1460
0.2    1467
0.4    1479
0.6    1494
0.8    1513
1.0    1725
Name: RecencyAgg, dtype: int64
1
2
3
4
5
6
7
8
9
10
11
# 2. 根据百分位数对数据进行分段,指定每组对应的分数
# 因为 cut 默认左开右闭,为了包含第一个数,设置为 0
bins[0] = 0
# 用户越久没消费 R 值就越小,分之就越小
rLabels = [5, 4, 3, 2, 1]
R_S = pd.cut(
aggData.RecencyAgg,
bins=bins,
labels=rLabels
)
R_S.head()
0    4
1    1
2    3
3    1
4    1
Name: RecencyAgg, dtype: category
Categories (5, int64): [5 < 4 < 3 < 2 < 1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 同样的原理求的 F 值
bins = aggData.FrequencyAgg.quantile(
q=[0, 0.2, 0.4, 0.6, 0.8, 1],
interpolation='nearest'
)
bins[0] = 0
# 用户消费频次越高 F 值就越大,分之就越大
fLabels = [1, 2, 3, 4, 5]
F_S = pd.cut(
aggData.FrequencyAgg,
bins=bins,
labels=fLabels
)
F_S.head()
0    4
1    2
2    4
3    4
4    1
Name: FrequencyAgg, dtype: category
Categories (5, int64): [1 < 2 < 3 < 4 < 5]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 同样的原理求的 M 值
bins = aggData.MonetaryAgg.quantile(
q=[0, 0.2, 0.4, 0.6, 0.8, 1],
interpolation='nearest'
)
bins[0] = 0
# 用户消费金额越高 M 值就越大,分之就越大
mLabels = [1, 2, 3, 4, 5]
M_S = pd.cut(
aggData.MonetaryAgg,
bins=bins,
labels=mLabels
)
M_S.head()
0    3
1    2
2    4
3    4
4    1
Name: MonetaryAgg, dtype: category
Categories (5, int64): [1 < 2 < 3 < 4 < 5]
1
2
3
4
aggData['R_S'] = R_S
aggData['F_S'] = F_S
aggData['M_S'] = M_S
aggData.head()
CustomerID RecencyAgg FrequencyAgg MonetaryAgg R_S F_S M_S
0 14568 1468 15 6255 4 4 3
1 14569 1558 12 5420 1 2 2
2 14570 1488 15 8261 3 4 4
3 14571 1528 15 8124 1 4 4
4 14572 1552 8 3334 1 1 1
1
2
# 计算 RFM 得分,然后使用分为 八个 分组
aggData['RFM'] = 100*R_S.astype(int) + 10*F_S.astype(int) + 1*M_S.astype(int)
1
aggData.head()
CustomerID RecencyAgg FrequencyAgg MonetaryAgg R_S F_S M_S RFM
0 14568 1468 15 6255 4 4 3 443
1 14569 1558 12 5420 1 2 2 122
2 14570 1488 15 8261 3 4 4 344
3 14571 1528 15 8124 1 4 4 144
4 14572 1552 8 3334 1 1 1 111
1
2
3
4
5
6
7
8
9
10
11
12
13
bins = aggData.RFM.quantile(
q=[0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1],
interpolation='nearest'
)
bins[0] = 0
# RFM 值越大,得分越高
rfmLabels = [1, 2, 3, 4, 5, 6, 7, 8]
aggData['level'] = pd.cut(
aggData.RFM,
bins,
labels = rfmLabels
)
aggData.head()
CustomerID RecencyAgg FrequencyAgg MonetaryAgg R_S F_S M_S RFM level
0 14568 1468 15 6255 4 4 3 443 6
1 14569 1558 12 5420 1 2 2 122 1
2 14570 1488 15 8261 3 4 4 344 5
3 14571 1528 15 8124 1 4 4 144 2
4 14572 1552 8 3334 1 1 1 111 1

至此, RFM 分析的计算就完成了,求解得到的 level 和客户类型的对应关系如下

R 值 F 值 M 值 客户类型 level
高价值客户 8
重点保持客户 7
重点发展客户 6
重点挽留客户 5
一般价值客户 4
一般保持客户 3
一般发展客户 2
潜在客户 1

最后我们看一下每个等级的人数

1
2
3
aggData.groupby(
by='level',
)['CustomerID'].agg('count')
level
1    153
2    164
3    135
4    153
5    154
6    142
7    151
8    148
Name: CustomerID, dtype: int64

矩阵分析

1
2
data = pd.read_csv('../data/cnbook/第五章/5.8 矩阵分析/矩阵分析.csv')
data.head()
号码 省份 手机品牌 通信品牌 手机操作系统 月消费(元) 月流量(MB)
0 166547114238 河北 HTC 神州行 Android 298.9 318.6
1 166423353436 河南 HTC 神州行 Android 272.8 1385.9
2 166556915853 福建 HTC 神州行 Android 68.8 443.6
3 166434728749 湖南 HTC 神州行 Android 4.6 817.3
4 166544742252 北京 HTC 神州行 Android 113.2 837.4
1
2
3
4
5
6
# 按照省份分组,对月平均消费进行统计
costAgg = data.groupby(
by='省份',
as_index=False
)['月消费(元)'].agg('mean')
costAgg.head()
省份 月消费(元)
0 上海 152.927748
1 云南 148.100832
2 内蒙古 154.427736
3 北京 148.895912
4 台湾 146.081277
1
2
3
4
5
6
# 按照省份分组,对月平均流量进行统计
dataAgg = data.groupby(
by='省份',
as_index=False
)['月流量(MB)'].agg('mean')
dataAgg.head()
省份 月流量(MB)
0 上海 1025.075667
1 云南 985.382830
2 内蒙古 997.965655
3 北京 1010.642977
4 台湾 1014.620346
1
2
aggData = costAgg.merge(dataAgg)
aggData.head()
省份 月消费(元) 月流量(MB)
0 上海 152.927748 1025.075667
1 云南 148.100832 985.382830
2 内蒙古 154.427736 997.965655
3 北京 148.895912 1010.642977
4 台湾 146.081277 1014.620346
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 画矩阵图
from matplotlib import font_manager
import matplotlib.pyplot as plt
# 生成字体属性,用来显示中文
font = font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=10
)
labelFont = font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=15
)
# 蓝色,作为点的颜色
mainColor = (91/255, 155/255, 213/255, 1)
# 灰色,作为文本的颜色
fontColor = (110/255, 110/255, 110/255, 1)
# 新建一个绘图窗口
fig = plt.figure()
# 设置坐标轴的最大值最小值
gap = 0.01
xMin = aggData['月消费(元)'].min()*(1-gap)
xMax = aggData['月消费(元)'].max()*(1+gap)
yMin = aggData['月流量(MB)'].min()*(1-gap)
yMax = aggData['月流量(MB)'].max()*(1+gap)
# 设置 x 轴和 y 轴的坐标轴范围
plt.xlim(xMin, xMax)
plt.ylim(yMin, yMax)
# 设置刻度,这里设置为空
plt.xticks([])
plt.yticks([])
# 绘制散点图
plt.scatter(
aggData['月消费(元)'],
aggData['月流量(MB)'],
s=100, # 设置点的大小
marker='o', # 设置点的样式
color=mainColor # 设置点的颜色
)
# 设置坐标轴的标签
plt.xlabel(
'人均月消费(元)',
color=fontColor,
fontproperties=labelFont
)
plt.ylabel(
'人均月流量(MB)',
color=fontColor,
fontproperties=labelFont
)
# 绘制分割线
# 竖线
plt.vlines(
x=data['月消费(元)'].mean(),
ymin=yMin,
ymax=yMax,
linewidth=1,
color=mainColor
)
# 横线
plt.hlines(
y=data['月流量(MB)'].mean(),
xmin=xMin,
xmax=xMax,
linewidth=1,
color=mainColor
)
# 标记象限
plt.text(xMax-0.5, yMax-5, 'I', color=fontColor, fontsize=15)
plt.text(xMin, yMax-5, 'II', color=fontColor, fontsize=15)
plt.text(xMin, yMin, 'III', color=fontColor, fontsize=15)
plt.text(xMax-0.6, yMin, 'IV', color=fontColor, fontsize=15)
# 添加省标签
for i, r in aggData.iterrows():
plt.text(
r['月消费(元)'] + 0.25,
r['月流量(MB)'] - 1,
r['省份'],
color=fontColor,
fontproperties=font
)
plt.show()

png

相关分析

研究的是两个变量之间的相互关系,计算相关系数

1
2
data = pd.read_csv('../data/cnbook/第五章/5.9 相关分析/相关分析.csv')
data.head()
小区ID 人口 平均收入 文盲率 超市购物率 网上购物率 本科毕业率
0 1 3615 3624 2.1 15.1 84.9 41.3
1 2 365 6315 1.5 11.3 88.7 66.7
2 3 2212 4530 1.8 7.8 92.2 58.1
3 4 2110 3378 1.9 10.1 89.9 39.9
4 5 21198 5114 1.1 10.3 89.7 62.6
1
2
# 计算人口和文盲率的相关性
data['人口'].corr(data['文盲率'])
0.10762237339473261
1
2
# 计算 超市购物率、网上购物率、文盲率、人口 之间的相关性
data[['超市购物率', '网上购物率', '文盲率', '人口']].corr()
超市购物率 网上购物率 文盲率 人口
超市购物率 1.000000 -1.000000 0.702975 0.343643
网上购物率 -1.000000 1.000000 -0.702975 -0.343643
文盲率 0.702975 -0.702975 1.000000 0.107622
人口 0.343643 -0.343643 0.107622 1.000000

回归分析

简单线性回归分析

一元线性回归
Y = a + bX + e e 为误差

1
2
data = pd.read_csv('../data/cnbook/第五章/5.10.2 简单线性回归分析/线性回归.csv')
data.head()
月份 广告费用(万元) 销售额(万元)
0 201601 29.7 802.4
1 201602 25.7 725.0
2 201603 20.6 620.5
3 201604 17.0 587.0
4 201605 10.9 505.0
1. 根据预测目标,确定自变量因变量
1
2
3
4
# 自变量
x = data[['广告费用(万元)']]
# 因变量
y = data[['销售额(万元)']]
2. 绘制散点图,确定回归模型类型
1
2
# 绘制散点图
data.plot('广告费用(万元)', '销售额(万元)', kind='scatter')
<matplotlib.axes._subplots.AxesSubplot at 0x11942fe10>

png

1
2
# 计算相关系数
data['广告费用(万元)'].corr(data['销售额(万元)'])
0.9377748050928367
3. 估计模型参数,建立回归模型

从散点图中可以看出两者有明显的线性关系,但是这些数据点不在一条直线上,只能尽可能拟合出一条直线,使得尽可能多的数据点落在
或者更加靠近这条拟合出来的直线上,也就是让它们拟合的误差尽量小,最小二乘法就是一个较好的计算方法。

1
2
3
4
5
6
7
from sklearn.linear_model import LinearRegression
# 建立模型
lrModel = LinearRegression()
# 使用自变量 x 和因变量 y 训练模型
lrModel.fit(x, y)
# 查看 回归系数、截距
lrModel.coef_, lrModel.intercept_
(array([[17.31989665]]), array([291.90315808]))
4. 对回归模型进行检验

精度,就是用来表示点和回归模型的拟合程度的指标,一般使用判定系数 R^2 来度量回归模型拟合精度,也称拟合优度或决定系数,在
简单线性回归模型中,它的值等于 y 值和模型计算出来的 y’ 值的相关系数 R 的平方,用来表示拟合得到的模型能够解释因变量变化的百分比
,R^2 越接近 1, 表示回归模型拟合效果越好。

1
2
# 计算模型的精度
lrModel.score(x, y)
0.8794215850669082

可以看到拟合效果还是非常不错的

5. 利用回归模型进行预测
1
2
3
# 生成预测需要的自变量
pX = pd.DataFrame({'广告费':[20]})
lrModel.predict(pX)
array([[638.30109101]])

多重线性回归分析

就是多个自变量的线性回归,分析方法和简单线性相似

1
2
data = pd.read_csv('../data/cnbook/第五章/5.10.3 多重线性回归分析/线性回归.csv')
data.head()
月份 广告费用(万元) 客流量(万人次) 销售额(万元)
0 201601 29.7 14.8 802.4
1 201602 25.7 12.6 725.0
2 201603 20.6 9.9 620.5
3 201604 17.0 7.6 587.0
4 201605 10.9 5.1 505.0
根据预测目标,确定自变量和因变量
1
2
3
4
# 定义自变量
x = data[['广告费用(万元)', '客流量(万人次)']]
# 定义因变量
y = data[['销售额(万元)']]
绘制散点图,确定回归模型类型
1
data.plot('广告费用(万元)', '销售额(万元)', kind='scatter')
<matplotlib.axes._subplots.AxesSubplot at 0x125e2fe10>

png

1
data['广告费用(万元)'].corr(data['销售额(万元)'])
0.9377748050928367
1
data.plot('客流量(万人次)', '销售额(万元)', kind='scatter')
<matplotlib.axes._subplots.AxesSubplot at 0x12654ac18>

png

1
data['客流量(万人次)'].corr(data['销售额(万元)'])
0.9213105695705346
估计模型参数,建立线性回归模型
1
2
3
4
5
6
from sklearn.linear_model import LinearRegression
# 创建线性回归模型
lrModel = LinearRegression()
lrModel.fit(x, y)
# 查看 回归系数、截距
lrModel.coef_, lrModel.intercept_
(array([[10.80453641, 13.97256004]]), array([285.60371828]))
对回归模型进行检验
1
lrModel.score(x, y)
0.9026563046475117

拟合效果非常不错

利用回归模型进行预测
1
2
3
4
5
6
# 生成预测需要的自变量
pX = pd.DataFrame({
'广告费':[20],
'客流量':[5]
})
pX
广告费 客流量
0 20 5
1
2
# 用模型进行预测
lrModel.predict(pX)
array([[571.55724658]])

数据可视化

散点图

1
2
data = pd.read_csv('../data/cnbook/第六章/6.2 散点图/散点图.csv')
data.head()
日期 购买用户数 广告费用 促销 渠道数
0 2014/1/1 2496 9.14 6
1 2014/1/2 2513 9.47 8
2 2014/1/3 2228 6.31 4
3 2014/1/4 2336 6.41 2
4 2014/1/5 2508 9.05 5
1
2
3
import matplotlib
import matplotlib.pyplot as plt
plt.scatter(data['广告费用'], data['购买用户数'])
<matplotlib.collections.PathCollection at 0x12652dd68>

png

颜色设置

1
2
3
4
5
6
7
# 设置 rgb
mainColor = (91/255, 155/255, 213/255, 1)
plt.scatter(
data['广告费用'],
data['购买用户数'],
color=mainColor
)
<matplotlib.collections.PathCollection at 0x129083080>

png

坐标轴设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建字体,用来显示中文
font = matplotlib.font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=10
)
# 设置坐标轴标签以及颜色和字体
plt.xlabel(
'广告费用',
color=mainColor,
fontproperties=font
)
plt.ylabel(
'购买用户数',
color=mainColor,
fontproperties=font
)
Text(0, 0.5, '购买用户数')

png

1
2
3
4
5
6
7
8
9
# 设置刻度样式
plt.xticks(
color=mainColor,
fontproperties=font
)
plt.yticks(
color=mainColor,
fontproperties=font
)
(array([0. , 0.2, 0.4, 0.6, 0.8, 1. ]), <a list of 6 Text yticklabel objects>)

png

散点样式设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 打开一个新的绘图窗口
plt.figure()
# 粉色,作为促销的点的颜色
pinkColor = (255/255, 0/255, 102/255, 1)
# 蓝色,作为不促销的点的颜色
blueColor = (91/255, 155/255, 213/255, 1)
# 绘制促销的点
plt.scatter(
data[data['促销'] == '是']['广告费用'],
data[data['促销'] == '是']['购买用户数'],
color=pinkColor,
marker='o' # 点样式
)
# 绘制不促销的点
plt.scatter(
data[data['促销'] == '否']['广告费用'],
data[data['促销'] == '否']['购买用户数'],
color=blueColor,
marker='x' # 点样式
)
<matplotlib.collections.PathCollection at 0x1291f04a8>

png

添加图例

1
plt.legend(labels=['促销', '不促销'], prop=font)
<matplotlib.legend.Legend at 0x129474a90>

png

完整绘图示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 打开一个新的绘图窗口
plt.figure()
# 创建字体,用来显示中文
font = matplotlib.font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=10
)
# 粉色,作为促销的点的颜色
pinkColor = (255/255, 0/255, 102/255, 1)
# 蓝色,作为不促销的点的颜色
blueColor = (91/255, 155/255, 213/255, 1)
# 绘制促销的点
plt.scatter(
data[data['促销'] == '是']['广告费用'],
data[data['促销'] == '是']['购买用户数'],
color=pinkColor,
marker='o' # 点样式
)
# 绘制不促销的点
plt.scatter(
data[data['促销'] == '否']['广告费用'],
data[data['促销'] == '否']['购买用户数'],
color=blueColor,
marker='x' # 点样式
)
# 设置坐标轴标签以及颜色和字体
plt.xlabel(
'广告费用',
color=mainColor,
fontproperties=font
)
plt.ylabel(
'购买用户数',
color=mainColor,
fontproperties=font
)
# 设置刻度样式
plt.xticks(
color=mainColor,
fontproperties=font
)
plt.yticks(
color=mainColor,
fontproperties=font
)
# 添加图例
plt.legend(labels=['促销', '不促销'], prop=font)
<matplotlib.legend.Legend at 0x12951bc88>

png

矩阵图

参考之前的矩阵分析绘图部分

折线图

1
2
data = pd.read_csv('../data/cnbook/第六章/6.4 折线图/折线图.csv')
data.head()
id reg_date id_num gender birthday
0 109899 2011-02-01 35042519920219007J 1992/2/19
1 109903 2011-02-01 43048119891223411D 1989/12/23
2 109904 2011-02-01 42010219880201313H 1988/2/1
3 109905 2011-02-01 44030619840213001E 1984/2/13
4 109906 2011-02-01 43070219870502103H 1987/5/2
1
2
3
4
5
6
7
8
9
10
11
data['reg_date'] = pd.to_datetime(
data['reg_date']
)
# 按照注册日期进行分组,按照 id 列进行计数统计
ga =data.groupby(
by='reg_date',
as_index=False
)['id'].agg('count')
ga.columns = ['注册日期', '注册用户数']
ga.head()
注册日期 注册用户数
0 2011-02-01 282
1 2011-02-02 272
2 2011-02-03 264
3 2011-02-04 256
4 2011-02-05 256
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import matplotlib
from matplotlib import pyplot as plt
mainColor = (91/255, 155/255, 213/255, 1)
# 坐标轴刻度的字体
font = matplotlib.font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=10
)
# 坐标轴标签的字体
labelFont = matplotlib.font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=20
)
# 设置 y 轴显示的范围
plt.ylim(0, 500)
# 设置标题
plt.title('注册用户数', color=mainColor, fontproperties=labelFont)
# 设置 x、y 轴的标签
plt.xlabel('注册日期', color=mainColor, fontproperties=labelFont)
plt.xlabel('注册用户数', color=mainColor, fontproperties=labelFont)
# 设置坐标轴刻度样式
plt.xticks(color=mainColor, fontproperties=font)
plt.yticks(color=mainColor, fontproperties=font)
# 绘制折线图 lw 设置线的宽度
plt.plot(ga['注册日期'], ga['注册用户数'], '-', lw=5, color=mainColor)
[<matplotlib.lines.Line2D at 0x12a557438>]

png

饼图

1
ga = pd.Series({'男':54785, '女':4316})
1
ga
男    54785
女     4316
dtype: int64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import matplotlib
from matplotlib import pyplot as plt
femaleColor = (91/255, 155/255, 213/255, 0.5)
maleColor = (91/255, 155/255, 213/255, 1)
# 坐标轴刻度的字体
font = matplotlib.font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=10
)
# 设置为圆形的饼图
plt.axis('equal')
plt.pie(
ga,
labels=['男', '女'],
colors=[maleColor, femaleColor],
autopct='%.1f%%', # 设置百分号
textprops={'fontproperties':font}
)
([<matplotlib.patches.Wedge at 0x1484e9748>,
  <matplotlib.patches.Wedge at 0x1484e9e48>],
 [Text(-1.0711775990020538, 0.25015705346081196, '男'),
  Text(1.0711775814360058, -0.2501571286789748, '女')],
 [Text(-0.5842786903647565, 0.1364493018877156, '92.7%'),
  Text(0.5842786807832758, -0.13644934291580443, '7.3%')])

png

柱状图

1
2
data = pd.read_csv('../data/cnbook/第六章/6.6 柱形图/柱形图.csv')
data.head()
号码 省份 手机品牌 通信品牌 手机操作系统 月消费(元) 月流量(MB)
0 166547114238 河北 HTC 神州行 Android 298.9 318.6
1 166423353436 河南 HTC 神州行 Android 272.8 1385.9
2 166556915853 福建 HTC 神州行 Android 68.8 443.6
3 166434728749 湖南 HTC 神州行 Android 4.6 817.3
4 166544742252 北京 HTC 神州行 Android 113.2 837.4
1
2
3
4
5
6
# 统计每个品牌的消费总额
result = data.groupby(
by='手机品牌',
as_index=False
)['月消费(元)'].agg('sum')
result.head()
手机品牌 月消费(元)
0 HTC 458171.6
1 三星 1009290.8
2 华为 25696.0
3 摩托罗拉 117623.1
4 联想 89443.7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import matplotlib
from matplotlib import pyplot as plt
plt.figure()
# 生成 x 轴的位置, 赋值给 index
index = [1, 2, 3, 4, 5, 6, 7, 8]
# 配置颜色
mainColor = (91/255, 155/255, 213/255, 1)
# 设置字体
font = matplotlib.font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=10
)
# 排序
sgb = result.sort_values(by='月消费(元)', ascending=False)
plt.bar(
index,
sgb['月消费(元)'],
color=mainColor
)
# 设置 x 轴刻度
plt.xticks(index, sgb.手机品牌, fontproperties=font)
([<matplotlib.axis.XTick at 0x148504470>,
  <matplotlib.axis.XTick at 0x129caaa20>,
  <matplotlib.axis.XTick at 0x129caada0>,
  <matplotlib.axis.XTick at 0x129cce630>,
  <matplotlib.axis.XTick at 0x1484fcac8>,
  <matplotlib.axis.XTick at 0x129cce828>,
  <matplotlib.axis.XTick at 0x129cd1390>,
  <matplotlib.axis.XTick at 0x129cd4198>],
 <a list of 8 Text xticklabel objects>)

png

条形图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import matplotlib
from matplotlib import pyplot as plt
plt.figure()
# 生成 y 轴的位置, 赋值给 index
index = [1, 2, 3, 4, 5, 6, 7, 8]
# 配置颜色
mainColor = (91/255, 155/255, 213/255, 1)
# 设置字体
font = matplotlib.font_manager.FontProperties(
fname='../data/cnbook/SourceHanSansCN-Light.otf',
size=10
)
# 排序
sgb = result.sort_values(by='月消费(元)', ascending=True)
plt.barh(
index,
sgb['月消费(元)'],
color=mainColor
)
# 设置 x 轴刻度
plt.yticks(index, sgb.手机品牌, fontproperties=font)
([<matplotlib.axis.YTick at 0x14872aeb8>,
  <matplotlib.axis.YTick at 0x14872a828>,
  <matplotlib.axis.YTick at 0x14873beb8>,
  <matplotlib.axis.YTick at 0x148761940>,
  <matplotlib.axis.YTick at 0x148761e10>,
  <matplotlib.axis.YTick at 0x1487cc320>,
  <matplotlib.axis.YTick at 0x1487cc7f0>,
  <matplotlib.axis.YTick at 0x148761a20>],
 <a list of 8 Text yticklabel objects>)

png

1
2
echo-ding wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!