数据处理
数据预处理方法
- 归一化
- 二值化
- 维度变换
- 去重
- 无效数据过滤
数据处理方法
- 数据排序
- 数据查找
- 数据统计分析
Python 标准库之 collections
from collections import Counter
a = (0, 1, 1, 1, 2, 3, 7, 7, 23)
# 实现Counter
def count_elements(seq):
hist = {}
for i in seq:
# 字典中没有i,返回默认值0
hist[i] = hist.get(i, 0) + 1
return hist
counted = count_elements(a)
print(counted) # {0: 1, 1: 3, 2: 1, 3: 1, 7: 2, 23: 1}
recounted = Counter(a)
print(recounted) # Counter({1: 3, 7: 2, 0: 1, 2: 1, 3: 1, 23: 1})
print(recounted.items() == counted.items()) # True
numpy
速度对比:
import time
import numpy as np
list_array = list(range(int(1e6)))
start_time = time.time()
python_array = [val*5 for val in list_array]
end_time = time.time()
print('Python array time:{}ms'.format(round((end_time-start_time)*1000,2)))
np_array = np.arange(1e6)
start_time1 = time.time()
np_array = np_array*5
end_time1 = time.time()
print('numpy array time:{}ms'.format(round((end_time1-start_time1)*1000,2)))
一些常用方法:
函数 | 说明 |
abs | 绝对值 |
sqrt | 平方根 |
square | 平方 |
exp | 指数e^x |
sign | 正负号:1、0、-1 |
ceil | 大于等于该元素的最小整数 |
floor | 小于等于该元素的最小整数 |
isnan | 哪些元素是非数字 |
一些常见的两个数组可用方法:
函数 | 说明 |
add | 两个数组的和 |
subtract | 第一个数组减去第二个数组 |
mutiply | 两个数组元素的乘积(不是矩阵乘法) |
divide | 第一个数组除以第二个数组 |
power | 第一个数组元素A,第二个数组元素B,A^B |
fmax | 两个元素各个位置上更大的那个 |
fmin | 两个元素各个位置上更小的那个 |
一些常用的统计方法:
函数 | 说明 |
sum | 数组所有元素的和 |
mean | 数组所有元素的平均值 |
std | 数组所有元素的标准差 |
min,max | 数组所有元素的最大或最小值 |
argmin,argmax | 数组所有元素的最小或最大值对应的位置 |
如何通过numpy生成序列数(sequences),重复数(repetitions)和随机数(random)
seed( ) 用于指定随机数生成时所用算法开始的整数值。
- 如果使用相同的seed()值,则每次生成的随即数都相同
- 如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同
- 设置的seed()值仅一次有效
# 起始位置和结束位置分别为1和50
np.linspace(start=1, stop=50, num=10, dtype=int)
# array([ 1, 6, 11, 17, 22, 28, 33, 39, 44, 50])
# 设置数组的精度为小数点后两位
np.set_printoptions(precision=2)
a = [1,2,3]
# 重复数组a两次
print('Tile: ', np.tile(a, 2)) # Tile: [1 2 3 1 2 3]
# 重复数组a每项两次
print('Repeat: ', np.repeat(a, 2)) # Repeat: [1 1 2 2 3 3
# 生成2行2列的[0,1)的随机数
print(np.random.rand(2,2))
# 生成[0,10)的2行2列的随机整数
print(np.random.randint(0, 10, size=[2,2]))
# 生成[0,1)的2行2列的随机数
print(np.random.random(size=[2,2]))
# 从给定的列表和对应的概率分布抽样10次
print(np.random.choice(['a', 'e', 'i', 'o', 'u'], size=10, p=[0.3, .1, 0.1, 0.4, 0.1]))
Histogram
Python实线
import random
# 纯Python实现histogram
def ascii_histogram(seq):
counted = count_elements(seq)
for k in sorted(counted):
print('{0:5d} {1}'.format(k, '+' * counted[k]))
random.seed(1)
vals = [1, 3, 4, 6, 8, 9, 10]
# `vals` 里面的数字将会出现5到15次
freq = (random.randint(5, 15) for _ in vals)
data = []
for f, v in zip(freq, vals):
data.extend([v] * f)
print(ascii_histogram(data))
从数学意义上来看,直方图是分箱到频数的一种映射,它可以用来估计变量的概率密度函数的
拉普拉斯分布
import numpy as np
np.random.seed(444)
np.set_printoptions(precision=3)
d = np.random.laplace
d = np.random.laplace(loc=15, scale=3, size=500)
print(d[:5])
# [18.406 18.087 16.004 16.221 7.358]
# p.histogram() 默认地使用10个相同大小的区间(箱),然后返回一个元组(频数,分箱的边界)
hist, bin_edges = np.histogram(d)
print(hist)
# [ 13 23 91 261 80 21 7 2 1 1]
print(bin_edges)
# [ 2.11 5.874 9.638 13.402 17.166 20.93 24.694 28.458 32.222 35.986 39.749]
print(hist.size, bin_edges.size)
# 10 11
Numpy到底是如何进行分箱的呢?
首先获取a列表的最小值和最大值,然后设置默认的分箱数量,最后使用Numpy的 linspace方法进行数据段分割。分箱区间的结果也正好与实际吻合,0到23均等分为10份,23/10,那么每份宽度为2.3
a = (0, 1, 1, 1, 2, 3, 7, 7, 23)
# 取a的最小值和最大值
first_edge, last_edge = a.min(), a.max()
# NumPy得默认设置,10个分箱
n_equal_bins = 10
bin_edges = np.linspace(start=first_edge, stop=last_edge, num=n_equal_bins + 1, endpoint=True)
# array([ 0. , 2.3, 4.6, 6.9, 9.2, 11.5, 13.8, 16.1, 18.4, 20.7, 23. ])
pandas
Series类型(一维)
import pandas as pd
import numpy as np
# 列表类型创建,index与列表元素个数一致
data1 = pd.Series([1,3,5,7])
# 字典类型创建,键是索引
dict_data = {
'bj':1,
'sh':2,
'sz':3,
}
index_list = ['sz','bj','sh']
data2 = pd.Series(dict_data,index=index_list)
# ndarray,索引和数据都可以通过ndarray类型创建
data3 = pd.Series(np.arange(5),index=np.arange(9,4,-1))
arrays = [['Falcon', 'Falcon', 'Parrot', 'Parrot'],
['Captive', 'Wild', 'Captive', 'Wild']]
index = pd.MultiIndex.from_arrays(arrays, names=('Animal', 'Type'))
data4 = pd.Series([390., 350., 30., 20.], index=index, name="Max Speed")
# size返回Series数据类型
data4.groupby("Type").size()
# 重复元素出现的次数
print(data1.value_counts())
# 检测哪些数据缺失
print(data1.isnull())
print(data1.notnull())
Series类型基本操作
- 使用 .index 获取索引,使用 .value 获取数据
- Series类型的操作类似Python字典类型
- 通过自定义索引访问
- 保留字in操作
- 使用get()方法
DataFrame类型(二维)
pandas.DataFrame.values
返回DataFrame的Numpy形式
迭代
a=pd.DataFrame({"a":["i","j","k","i","j","k"],"b":[2,1,4,1,2,4],"c":[3,2,2,1,2,3]})
'''
a b c
0 i 2 3
1 j 1 2
2 k 4 2
3 i 1 1
4 j 2 2
5 k 4 3
'''
# 迭代(列名,序列)
for i in a.items():
print(i)
'''
('a', 0 i
1 j
2 k
3 i
4 j
5 k
Name: a, dtype: object)
('b', 0 2
1 1
2 4
3 1
4 2
5 4
Name: b, dtype: int64)
('c', 0 3
1 2
2 2
3 1
4 2
5 3
'''
Name: c, dtype: int64)
# 将行作为(索引,序列)进行迭代
for j in a.iterrows():
print(j)
'''
(0, a i
b 2
c 3
Name: 0, dtype: object)
(1, a j
b 1
c 2
Name: 1, dtype: object)
(2, a k
b 4
c 2
Name: 2, dtype: object)
(3, a i
b 1
c 1
Name: 3, dtype: object)
(4, a j
b 2
c 2
Name: 4, dtype: object)
(5, a k
b 4
c 3
Name: 5, dtype: object)
'''
API
import pandas as pd
import numpy as np
# 从二维ndarray对象创建
data1 = pd.DataFrame(np.arange(10).reshape(2,5))
# 从列表类型的字典创建
dict_data = {
'one':['xx','qq','ee','hh'],
'two':[88,99,66,77],
'three':['F','F','M','F'],
}
data2 = pd.DataFrame(dict_data, index=['a','b','c','d'])
# 获取第1列数据
print(data2.iloc[0])
# 删除第1列数据
del data2['one']
data2 = data2.reindex(index=['b','a','d','c'],fill_value=0)
#扔掉包含缺失的数据(NaN)的行
print(data2.dropna())
#填充所有缺失数据为一个值
print(data2.fillna(0))
# 删除索引为d的那一行数据
data2 = data2.drop('d')
# 筛选数据
print(data2[data2['two']>=90])
# 利用groupby对数据进行分组
data3 = pd.DataFrame({
"tag_id":["a","a","c","b","b","c"],
"count":[10,12,20,30,10,50]
})
# 按count 列进行降序排序 可以设置inplace=True 对原数据框应用该排序操作
print(data3.sort_values(by='count',ascending=False))
print(data3.sort_index(ascending=False, inplace=True))
data3 = data3.groupby("tag_id")
print(data3.sum())
DataFrame类型基本操作
- 获取某一列的值:loc根据index来索引,iloc根据行号来索引,行号从0开始,逐次加一
- 注意:切换得到的数据对应还是原始数据,任何修改都会反映到原始数据上
- 删除DataFrame中某一列数据 del
- .reindex()能够改变或重排Series和DataFrame索引
- 将缺失位置填0:fill_value=0;缺失位置通过插值法补上内容,method=ffill 从前面数据计算插值,method=bfill 从后面数据计算插值,丢弃数据dropna,填充数据fillna(0)
- 删除某一行数据 drop()
- 利用groupby对数据进行分组运算
一些常用的方法:
函数 | 说明 |
count | 非NaN数据的数量 |
min、max | 最大、最小值 |
argmin、argmax | 最大、最小值位置 |
sum | 数值的和 |
mean | 平均数 |
median | 中位数 |
var | 方差 |
std | 标准差 |
describe | 分位数 |
Pandas文件读取
csv 和xls 数据读取
- sep 用来定义分隔符
- names 用来自定义列表
- dtype 来定义列的类型,特别是想改变默认类型的时候
dtype={"score":int}
- parse_dates 自动解析时间数据
- encoding 用来解析数据使用的编码格式,主要在xls转换成csv数据时常用
- utf-8、gb2313、gbk、gb18030
- chunksize 当数据超出内存总量时通过设置chunksize来分段读取其中部分,chunksize用来定义一次读取的行数
import pandas as pd
# 默认把第一行当标题行读取
data = pd.read_csv('1.csv',header=None)
# 指定索引行,指定分隔符为制表符
# 通过parse_dates自动解析时间数据,[3]代表解析3号位也就是第四列数据cv
data = pd.read_csv('1.csv',names=["name",'gender','score'],index_col="name",sep="\t", parse_dates=[3])
# 存储数据为csv文件
data = pd.DataFrame({
"key": ["a","b","c"],
"data": [1,2,3]
})
data.to_csv('2.csv')
# 读取excel
file = pd.ExcelFile("2.xlsx")
data = file.parse("sheet1")
print(data)
json 数据读取
多层结构可以使用 json_normalize 进行进一步的解析,对于无法对应的列默认置空
import pandas as pd
from pandas.io.json import json_normalize
d = pd.read_json(r'F:\shoes1.json')
c = json_normalize(d["info"])
print(c['货号'])
字符串处理
如果数据类型不是int,(dtype: str/object),需要改变对应列类型才能求均值,具体改变方法见链接
# astype强制转换
data.price.astype(float).mean()
# 使用to_numeric转为数值
pd.to_numeric(data.price).mean()
- python 原生字符串处理常用函数: len、split、replace
- pandas Series.str 字符串处理,详见链接:–K/p/8443995.html
- 常用函数:split、replace、contains、extract
- 注意:contains的结果是一个二分序列
- expand表示是否把series类型转化为DataFrame类型
import pandas as pd
import numpy as np
import json
from pandas.io.json import json_normalize
root_path = r'F:\shoes\shoes.json'
op1 = open(root_path,encoding='utf-8')
li = []
dict1 = []
for i in op1:
# 把字符串转换为json
k = json.loads(i.encode('utf-8'))
li.append(k)
# 把由json数据构成的列表转换成数据框
a = json_normalize(li)
a.isnull().sum()
# 使用to_numeric转为数值类型,常用astype
pd.to_numeric(a.price).describe()
# 去掉付款人数后面的汉字保留数字
a.sales.str.split("人",expand=True)[0].astype(int).describe()
# 过滤所有title里面有2018的商品
a[a.title.str.contains("2018")].title
# 正则表达式,抽取所有匹配到的数字
a.title.str.extract('(\d+)').head()
# 求各个省份的商品数量
p0 = a.groupby(a.location.str.split(" ",expand=True)[0]).size()
# 转换成列表
p0.tolist()
p0.index.tolist()
# 求出各个市的商品数量
a.groupby(a.location.str.split(" ",expand=True)[1]).size()
# 求出商品“info.鞋面材质”中各个特征的商品数量
a.groupby('info.鞋面材质').size()
# 求所有商品的的总付款人数(注意同样要进行类型转换)
a.sales.str.split("人",expand=True)[0].astype(int).sum()
# 选择title中包含春季的商品前五行
a[a.title.str.contains("春季")].head(5)
# 求出所有在"info.颜色分类"中有白色的商品,并求出其数量
len(a[a["info.颜色分类"].str.contains("白色")])
Pandas数据合并
- 平均(mean),求和(sum),最大值(max),最小值(min),中位数(median),方差(var),标准差(std),累乘(prod),first,last,mean,median(中位数),mad(均值绝对偏差)
- describe
- size 求行数
pd.concat([a1,b1])
纵向合并。列标对齐,不改变本身次序,行标没有改变
pd.concat([a1,b1],axis=1,join="inner")
横向合并
- 直接抛弃置空的所在行,则需要使用join这个参数
- 如果希望抛弃原来的索引,重建新的顺序索引的话可以用ignore_index
- axis=1 由纵向合并变换成横向合并
r1['name'].str.split('_', expand=True)
这样返回一个DataFrame结构,如果未设置expand,返回时一个Series结构
pd.merge
基于值得数据合并
import numpy as np
import pandas as pd
a=pd.DataFrame({"a":["i","j","k","i","j","k"],"b":[2,1,4,1,2,4],"c":[3,2,2,1,2,3]})
for i in a.iterrows():
if i[1].b+i[1].c>5:
print(i[1])
# 推荐使用
print(a[a.b+a.c>5])
a=np.array([[2,4],[7,1]])
b=np.array([[3,5],[2,7]])
# 将数组转换成数据框并进行横向的合并
a1=pd.DataFrame(a,index=[1,2],columns=["i","j"])
b1=pd.DataFrame(b,index=[1,2],columns=["i","j"])
pd.concat([a1,b1])
root_path = "F:\t_alibaba_data3\t_alibaba_data3.txt"
r1=pd.read_csv(root_path,names=["user","brand","behavr","date"],sep="\t",dtype={"behavr":int})
# 通过字符串的处理分离出月份序列,并把这个序列通过合并的方式作为一列并入r1
pd.concat([r1,r1.date.str.split("/",expand=True)[0]],axis=1)
r1 = r1.rename(columns = {0:"month"})
pd.DataFrame({"浏览":r1[r1.behavr==0].groupby("brand").size(),"购买":r1[r1.behavr==1].groupby("brand").size()})
r1.head()
data1 = pd.DataFrame({
"key":["a","b","a","c","b","d"],
"data1":[1,2,3,4,5,6]
})
data2 = pd.DataFrame({
"key":["a","b","c"],
"data2":[7,8,9]
})
#不指定连接方式 共有的才输出
print(pd.merge(data1,data2))
#有的都输出
print(pd.merge(data1,data2,how="outer"))
# 按照指定连接的列名称
print(pd.merge(data1,data2,on="key"))
pyecharts
pyecharts 是一个用于生成 Echarts 图表的类库。Echarts是百度开源的一个数据可视化 JS 库
优点:
- 与Echarts结合
- 与Web端结合
- 超强交互性
- 国人开发的项目
图表绘制流程:
-
chart_name = 图表类型()
初始化具体类型图表。 chart_name.add()
添加数据及配置项
-
chart_name.add_xaxis()
添加横坐标名称 -
chart_name.add_yaxis()
添加纵坐标数据
-
chart_name.render()
渲染生成 .html 文件
导入pyecharts模块及随机虚构数据模块
from pyecharts.faker import Faker #创建虚构的数据
from pyecharts import options as opts #配置
from pyecahrts.charts import Bar #bar图
from pyecharts.globals import ThemeType #设置主题
bar.add_xaxis(list(x))
bar.add_yaxis("name", y)
全局配置项
全局配置项可通过 get_global_options
方法设置
- InitOpts:初始化配置项
- TitleOpts:标题配置项
- AxisOpts:坐标轴配置项
- DataZoomOpts:区域缩放配置项
- LegendOpts:图例配置项
- VisualMapOpts:视觉映射配置项
注意数据得到的是python的list/列表类型,如果是numpy的数组需要转换为list
from pyecharts.faker import Faker
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType
# 实例化 柱状图/条形图
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.CHALK))
# 生成随机数据
# add_xaxis(x轴标签列表)
bar.add_xaxis(Faker.choose())
# add_yaxis(名称,y轴数据列表)
# 两两堆叠制作效果图 stack1堆2数据
bar.add_yaxis("name1", Faker.values(),stack="stack1")
bar.add_yaxis("name2",Faker.values(),stack="stack1")
# 标题 subtitle 副标题
bar.set_global_opts(title_opts=opts.TitleOpts(title="Bar"),
# 让标识偏移
legend_opts=opts.LegendOpts(pos_left="20%"),
# 旋转x轴标签
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=30)),
# 窗口滑块
datazoom_opts=opts.DataZoomOpts(is_show=True),)
# 不显示数字
bar.set_series_opts(label_opts=opts.LabelOpts(is_show=False),
# 标记点
markpoint_opts=opts.MarkPointOpts(
data=[
opts.MarkPointItem(type_="max", name="最大值"),
opts.MarkPointItem(type_="min", name="最小值"),
]
),
# 标记线
markline_opts=opts.MarkLineOpts(
data=[
opts.MarkLineItem(type_="average", name="平均值"),
]
))
bar.render_notebook()
系列配置项
系列配置项可通过 set_series_opts
方法设置
练习:
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType
x=range(1,8)
y=[114, 55, 27, 101, 125, 27, 105]
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.ESSOS))
bar.add_xaxis(list(x))
bar.add_yaxis("name",y)
# 翻转 XY 轴数据
bar.reversal_axis()
bar.set_series_opts(label_opts=opts.LabelOpts(font_style="italic",font_size=20),
markline_opts=opts.MarkLineOpts(
data=[
opts.MarkLineItem(type_="max", name="最大值"),
opts.MarkLineItem(type_="min", name="最小值"),
opts.MarkLineItem(type_="average", name="平均值"),
]
))
bar.set_global_opts(yaxis_opts=opts.AxisOpts(max_=135))
bar.render_notebook()
pyecharts数据类型问题
https://pyecharts.org/#/zh-cn/data_format
由于pyecharts背后封装的js库,会涉及到数据类型转换。它暂时需要输入数据必须是python的基础数据类型,比如字符串,列表,字典,而不能是序列这样的数据类型,因此序列输入量需要事先呗转化为list等基础数据类型才能被pyecharts支持
pandas数据类型转换成python数据类型 tolist()
zip(a,b)
zip()函数分别从a和b依次各取出一个元素组成元组,再将依次组成的元组组合成一个新的迭代器–新的zip类型数据
图标类型
基本图表
直角坐标系图表
组合图表
3D图表
多维数据可视化1
import json
import pandas as pd
from pandas.io.json import json_normalize
op1 = open(r'D:\shoes\shoes.json','r',encoding='utf-8')
li = []
dict1 = {}
for i in op1:
k = json.loads(i.encode('utf-8'))
li.append(k)
a = json_normalize(li)
a.groupby("nick").size().sort_values(ascending=False)
#计算上面排名前二的两个商家各个款式的对应的商品数量,并且组成矩阵,使得第一列是"意尔康皮鞋旗舰店"对应的商品数量,第二列是"米兰多格商场"的
t1 = a[a.nick=="意尔康皮鞋旗舰店"].groupby("info.款式").size()
t2 = a[a.nick=="米兰多格商场"].groupby("info.款式").size()
p0 = pd.concat([t1,t2], axis=1,sort=False).fillna(0)
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.charts import Bar, Grid, Line, Scatter, Tab, Timeline
from pyecharts.charts import Page, Pie, Funnel
# 直角坐标系
# f1 = Line(init_opts=opts.InitOpts(theme=ThemeType.ESSOS)).add_xaxis(p0.index.tolist()).add_yaxis("name",p0.tolist())
# f1.set_global_opts(title_opts = opts.TitleOpts(title="意尔康男鞋分析"))
# f1.render_notebook()
# 饼图
# f2=Pie().add("", [list(z) for z in zip(p0.index.tolist(), p0.tolist())])
# f2.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
# f2.set_global_opts(
# title_opts=opts.TitleOpts(title="意尔康男鞋分析"),
# legend_opts=opts.LegendOpts(
# orient="vertical", pos_top="15%", pos_left="2%"
# ),
# )
# f2.render_notebook()
# 漏斗图
# f3 = Funnel().add("", [list(z) for z in zip(p0.index.tolist(), p0.tolist())],
# sort_ = 'ascending',
# label_opts=opts.LabelOpts(position="inside"))
# f3.set_global_opts(title_opts=opts.TitleOpts(title="意尔康男鞋分析"),
# legend_opts=opts.LegendOpts(
# orient="vertical", pos_top="15%", pos_left="2%"
# ),
# )
# f3.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
# f3.render_notebook()
########################################
# 组合图表
f1 = Bar(init_opts=opts.InitOpts(theme=ThemeType.PURPLE_PASSION))
f1.add_xaxis(p0.index.tolist())
f1.add_yaxis("意尔康皮鞋旗舰店",p0[0].tolist())
f1.set_global_opts(title_opts=opts.TitleOpts(title="Grid"),legend_opts=opts.LegendOpts(pos_left="20%"))
f2 = Line(init_opts=opts.InitOpts(theme=ThemeType.PURPLE_PASSION))
f2.add_xaxis(p0.index.tolist())
f2.add_yaxis("米兰多格商场",p0[1].tolist())
f2.set_global_opts(title_opts=opts.TitleOpts(title="Grid"))
# 并行多图
# g1 = Grid(init_opts=opts.InitOpts(theme=ThemeType.PURPLE_PASSION))
# g1.add(f1,grid_opts=opts.GridOpts(pos_left="55%"))
# g1.add(f2,grid_opts=opts.GridOpts(pos_right="55%"))
# 组合图表
# tab1 = Tab()
# tab1.add(f1, "意尔康皮鞋旗舰店")
# tab1.add(f2, "米兰多格商场")
# 时间轮播图
t1 = Timeline()
t1.add(f1, "意尔康皮鞋旗舰店")
t1.add(f2, "米兰多格商场")
t1.render_notebook()
多维数据可视化2
import json
import pandas as pd
from pandas.io.json import json_normalize
op1 = open(r'D:\shoes\shoes.json','r',encoding='utf-8')
li = []
dict1 = {}
for i in op1:
k = json.loads(i.encode('utf-8'))
li.append(k)
a = json_normalize(li)
p0 =a.groupby(["info.鞋面材质","info.风格"]).size().sort_values(ascending=False)
from pyecharts import options as opts
from pyecharts.charts import Bar3D, HeatMap
x = []
y = []
data = []
for i in p0.iteritems():
if i[0][0] not in x:
x.append(i[0][0])
if i[0][1] not in y:
y.append(i[0][1])
data.append([x.index(i[0][0]),y.index(i[0][1]),i[1]])
# 3D柱状图
# f1 = Bar3D()
# f1.add("",data,
# xaxis3d_opts=opts.Axis3DOpts(x, type_="category"),
# yaxis3d_opts=opts.Axis3DOpts(y, type_="category"),
# zaxis3d_opts=opts.Axis3DOpts(type_="value"),)
# f1.set_global_opts(visualmap_opts=opts.VisualMapOpts(max_=20),
# title_opts=opts.TitleOpts(title="Bar3D-基本示例"))
# 热图
f2 = HeatMap()
f2.add_xaxis(x)
f2.add_yaxis("series", y, data)
f2.set_global_opts(title_opts=opts.TitleOpts(title="HeatMap-基本示例"),
visualmap_opts=opts.VisualMapOpts(),)
f2.render_notebook()
多维数据可视化3
import json
import pandas as pd
from pandas.io.json import json_normalize
import numpy as np
op1 = open(r'D:\shoes\shoes.json','r',encoding='utf-8')
li = []
dict1 = {}
for i in op1:
k = json.loads(i.encode('utf-8'))
li.append(k)
a = json_normalize(li)
a.sales = a.sales.str.split('人', expand=True)[0]
a.sales = a_sales.astype(np.int64)
a.price = a.price.astype(np.float)
z1 = a.sales*a.price
z1.name = "xse"
a1 = pd.concat([a,z1],axis=1)
# a1.head(2)
# 先做成字典,把各个特征放入字典中
te_zheng = {"nick":[],"z_xse":[],"z_num":[],"p_sales":[],"p_bdj":[],"p_price":[]}
for i in a1.groupby("nick"):
te_zheng["nick"].append(i[0])
te_zheng["z_xse"].append(i[1].xse.sum())
te_zheng["z_num"].append(len(i[1]))
# 求平均值
te_zheng["p_sales"].append(round(i[1].sales.mean(),1))
# 笔单价 存在除零的情况,所以做判断
if i[1].sales.sum() == 0:
te_zheng["p_bdj"].append(0)
else:
te_zheng["p_bdj"].append(round(i[1].xse.sum()/i[1].sales.sum(),1))
te_zheng["p_price"].append(round(i[1].price.mean(),1))
from pyecharts.charts import Scatter
from pyecharts.charts import Page, Parallel
# f1=Scatter(init_opts=opts.InitOpts(theme=ThemeType.PURPLE_PASSION))
# f1.add_xaxis(df_te_zheng[0:20].z_xse.tolist())
# f1.add_yaxis("商家A",df_te_zheng[0:20].p_bdj.tolist())
# 注意pyechart的x轴通常默认为类别轴,需要重新设定为数值轴
# 类别轴只管字符串排序 不管其位置
# f1.set_global_opts(xaxis_opts=opts.AxisOpts(type_='value'),datazoom_opts=opts.DataZoomOpts(is_show=True))
# f1.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
# f1.render_notebook()
z1 = df_te_zheng.head(5)
data1=[]
for i in z1.iterrows():
data1.append(i[1].tolist()[1:])
f2 = Parallel().add_schema(
[
# 注意这里的序号对应于data1中列表的索引
{"dim":0, "name":"z_xse"},
{"dim":1, "name":"z_num"},
{"dim":2, "name":"p_sales"},
{"dim":3, "name":"p_bdj"},
{"dim":4, "name":"p_price"},
]
)
f2.add("parallel", data1)
f2.set_global_opts(title_opts=opts.TitleOpts(title="Parallel-基本示例"))
f2.render_notebook()
统计分布与数据可视化
value_counts(bin=500) bin是指在最小值和最大值之间选择500个区间,然后统计在各个区间内的商品数量,pandas.Interval 类型(区间),是闭合的,区间可以求中值(mid)
import numpy as np
import pandas as pd
import json
from pandas.io.json import json_normalize
from collections import Counter
op1=open(r'D:\数据分析与可视化数据\shoes\shoes.json', 'r',encoding='utf-8')
li=[]
dict1={}
for i in op1:
k = json.loads(i.encode("utf-8"))
li.append(k)
a = json_normalize(li)
a.sales = a.sales.str.split("人",expand=True)[0]
a.sales = a.sales.astype(np.int64)
a.price = a.price.astype(np.float)
p1 = a.price.value_counts()
# 这里没有按照值大小进行排序,如果排序会破坏曲线的状态
p2 = a.sales.value_counts(bins=500,sort=False)
x=[]
y=[]
for i in p2.items():
x.append(i[0].mid)
y.append(i[1])
from pyecharts.globals import ThemeType
from pyecharts import options as opts
from pyecharts.charts import Line
# is_smooth 是否平滑曲线
f1 = Line().add_xaxis(x).add_yaxis("price", y, is_smooth=True)
f1.set_global_opts(title_opts=opts.TitleOpts(title="意尔康男鞋分析"),
xaxis_opts=opts.AxisOpts(type_="value"),
datazoom_opts=opts.DataZoomOpts(is_show=True))
f1.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
# 淘宝商品价格分布的双峰特征明显
f1.render_notebook()
基于histogram进行含权统计
- 假如我们不仅想知道某个区间的商品数量,并且还想知道在此区间商品的销售情况,这样就需要引入销量作为权值进行含权统计
- histogram能统计区间的数量,并且更强大的在于能够进行含权统计
import numpy as np
import pandas as pd
import json
from pandas.io.json import json_normalize
from collections import Counter
op1=open(r'D:\数据分析与可视化数据\shoes\shoes.json', 'r',encoding='utf-8')
li=[]
dict1={}
for i in op1:
k = json.loads(i.encode("utf-8"))
li.append(k)
a = json_normalize(li)
a.sales = a.sales.str.split("人",expand=True)[0]
a.sales = a.sales.astype(np.int64)
a.price = a.price.astype(np.float)
p1 = a.price.value_counts()
# 这里没有按照值大小进行排序,如果排序会破坏曲线的状态
p2 = a.sales.value_counts(bins=500,sort=False)
# 求"info.鞋面材质"为"头层牛皮(除牛反绒)"的商品的价格分布
x2 = []
y2 = []
for i in p2.items():
x2.append(i[0].mid)
y2.append(i[1])
s1 = a[a["info.鞋面材质"]=="头层牛皮(除牛反绒)"].price.value_counts(bins=400).sort_index()
x1 = []
y1 = []
for i in s1.items():
x1.append(i[0].mid)
y1.append(i[1])
# 求各个店铺的商品数量分布图
# n1 = a.groupby("nick").size().value_counts().sort_index()
# y = n1.tolist()
# x = n1.index.tolist()
y,x = np.histogram(a.price.values,np.linspace(a.price.min(),700,50),weights=a.sales.values)
# 由于上面区间值比区间要多一个数,为了对应在区间量里增加了一个值,以满足对应要求
f1=Line().add_xaxis(x.tolist()).add_yaxis("price", [0]+y.tolist(),is_smooth=True)
f1.set_global_opts(title_opts=opts.TitleOpts(title="意尔康男鞋分析"),
xaxis_opts=opts.AxisOpts(type_="value"),
datazoom_opts=opts.DataZoomOpts(is_show=True))
f1.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
# 200左右极大值相比300左右极大值区间,前者商品数量多但是后者在商品数量少的情况下一点不逊色,说明300左右的竞争力小很多
f1.render_notebook()
通过箱型图来可视化了解分位数情况
- apply作为一种基于数据框的函数的遍历方法,能把函数自动作用到groupby的每一个组
import json
import pandas as pd
from pandas.io.json import json_normalize
op1=open(r'D:\数据分析与可视化数据\shoes\shoes.json', 'r',encoding='utf-8')
li=[]
dict1={}
for i in op1:
k = json.loads(i.encode("utf-8"))
li.append(k)
a = json_normalize(li)
a.groupby("info.鞋面材质").size()
def c1(x):
return x.price.values
p3 = a.groupby("info.鞋面材质").apply(c1)
from pyecharts.charts import Boxplot
x=["PU","二层牛皮(除牛反绒)","头层牛皮(除牛反绒)","人造革"]
y=[p3[x[0]],p3[x[1]],p3[x[2]],p3[x[3]]]
c = Boxplot()
c.add_xaxis(x).add_yaxis("A", c.prepare_data(y))
c.set_global_opts(title_opts=opts.TitleOpts(title="BoxPlot-基本示例"))
c.render_notebook()
#头层牛皮最贵
#材质越差,价格波动空间越小,好材质,定价空间更大
时间数据可视化
date类是一个时间类,由年、月、日组成。
类的构造函数如下:class datetime.date(year, month, day)
给日期加一个时间间隔(datetime.timedelta
类的对象)
date.fromtimestamp()
函数:根据给定的时间戳,返回一个date对象
import datetime
import randint
import time
now = datetime.date.today()
a = datetime.timedelta(days=10)
b = now+b
now = time.time()
s = datetime.date.fromtimestamp(now)
begin = datetime.date(2017, 1, 1)
end = datetime.date(2017, 12, 31)
data = [
[str(begin + datetime.timedelta(days=i)), random.randint(1000, 25000)]
for i in range((end - begin).days + 1)
]
数据结构:[str(begin + datetime.timedelta(days=i)), random.randint(1000, 25000)] for i in range((end - begin).days + 1)
import pandas as pd
r1 = pd.read_csv(r"D:\数据分析与可视化数据\t_alibaba_data3\t_alibaba_data3.txt",names=["user","brand","behavr","date"],sep="\t",dtype={"behavr":int})
r1.date = "2011/" + r1.date
r1.date = pd.to_datetime(r1.date)
t1 = r1.groupby(pd.Grouper(key="date")).size()
t1.sort_index(inplace=True)
from pyecharts.charts import Line
f1=Line().add_xaxis(t1.index.tolist()).add_yaxis("price", t1.tolist(),is_smooth=True)
f1.set_global_opts(title_opts=opts.TitleOpts(title="意尔康男鞋分析"),
xaxis_opts=opts.AxisOpts(type_="time"))
f1.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
f1.render_notebook()
from pyecharts import options as opts
from pyecharts.charts import Calendar
c1 = Calendar()
c1.add("", data, calendar_opts=opts.CalendarOpts(range_=["2011-04-15","2011-08-15"]))
c1.set_global_opts(
title_opts=opts.TitleOpts(title="Calendar-2011年品牌销售量"),
visualmap_opts=opts.VisualMapOpts(
max_=3000,
min_=40,
orient="horizontal",
# 是否为分段型
is_piecewise=True,
pos_top="230px",
pos_left="100px",
),
)
c1.render_notebook()
pyecharts基于page的布局
from pyecharts.globals import ThemeType
from pyecharts.faker import Faker
from pyecharts import options as opts
from pyecharts.charts import Bar, Grid, Line, Page, Pie
bar1 = Bar(init_opts=opts.InitOpts(theme=ThemeType.PURPLE_PASSION))
bar1.add_xaxis(['comments_count','reposts_count','attitudes_count'])
bar1.add_yaxis("韩寒", [1265,495,3931])
bar1.add_yaxis("蔡徐坤", [42,159,202])
bar1.set_global_opts(title_opts=opts.TitleOpts(title="转发反馈统计"),toolbox_opts=opts.ToolboxOpts())
bar2 = Bar(init_opts=opts.InitOpts(theme=ThemeType.PURPLE_PASSION))
bar2.add_xaxis(['repost'])
bar2.add_yaxis("韩寒", [32585])
bar2.add_yaxis("蔡徐坤", [22630])
bar2.set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况"),toolbox_opts=opts.ToolboxOpts())
page = Page(layout=Page.DraggablePageLayout)
# 需要自行调整每个 chart 的 height/width,显示效果在不同的显示器上可能不同
page.add(bar1,bar2)
page.render()
#运行上面代码后会在下面的目录中出现一个render.html文件,文件里包含上面两张图,打开此html文件,可以拖动图形到你想要的位置
#拖动完成后点击左上角的save config,然后会在你的浏览器下载目录里生成一个“chart_config.json”文件
#如果目录下已经有了此文件会生成的是chart_config (1),注意再windows系统下建议把chart_config (1)中的空格去掉,这样的文件名才符合规范
page.save_resize_html("render.html", cfg_file=r"C:\Users\Downloads\chart_config3.json", dest="my_new_charts.html")
#拖动完成后再下面输出上面命令,运行则会生成按照你的要求布局的可视化html文件
地图与地理坐标可视化
数据结构:[list(z) for z in zip(Faker.provinces, Faker.values())]
经纬度查询:https://www.toolnb.com/tools/getbaidupoint.html
import numpy as np
import pandas as pd
import json
from pandas.io.json import json_normalize
import pyecharts as pe
from collections import Counter
# 官网的案例
from pyecharts.faker import Faker
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.globals import ChartType, SymbolType
g0 = Geo()
g0.add_schema(maptype="浙江")#可以通过maptype来选择具体省市的地图
g0.add("geo", [["杭州",50],["宁波",30],["义乌",20],["萧山",99]])
g0.set_series_opts(label_opts=opts.LabelOpts(is_show=False))#去掉标识
g0.set_global_opts(
visualmap_opts=opts.VisualMapOpts(is_piecewise=True,max_=300),
title_opts=opts.TitleOpts(title="Geo-基本示例"),
)
g0.render_notebook()
from pyecharts.globals import GeoType
city = '杭州'
g = Geo()
g.add_schema(maptype=city)
# 定义坐标对应的名称,添加到坐标库中 add_coordinate(name, lng, lat)
g.add_coordinate('杭州师范大学仓前校区',120.0109472358, 30.2910373720)#注意这里要求经度在前维度在后
g.add_coordinate('萧山城厢街道',120.2740081170, 30.1605364542)
# 定义数据对
data_pair = [('杭州师范大学仓前校区', 10),('萧山城厢街道', 5),("杭州",50)]
# Geo 图类型,有 scatter, effectScatter, heatmap, lines 4 种,建议使用
# from pyecharts.globals import GeoType
# GeoType.GeoType.EFFECT_SCATTER,GeoType.HEATMAP,GeoType.LINES
# 将数据添加到地图上
g.add('', data_pair, type_=GeoType.EFFECT_SCATTER, symbol_size=15)
# 设置样式
g.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
# 自定义分段 color 可以用取色器取色
pieces = [
{'max': 6, 'label': '5以下', 'color': '#FF00FF'},
{'min': 6, 'max': 10, 'label': '5-10', 'color': 'yellow'},
{'min': 10, 'max': 100, 'label': '10-100', 'color': 'red'} # 有下限无上限
]
# is_piecewise 是否自定义分段, 变为true 才能生效
g.set_global_opts(
visualmap_opts=opts.VisualMapOpts(is_piecewise=True, pieces=pieces),#注意默认max_
title_opts=opts.TitleOpts(title="{}-店铺分布".format(city)),
)
g.render_notebook()