本案例重点有二:
重点一在于如何修改数据类型以降低内存占用,这对大数据非常重要;
重点二在于分析变量之间的关系,单变量分布,双变量相关或方差分析,多变量回归或分类;
一、数据基本信息
#导入必要的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")
#指定工作路径以导入数据或者存入数据
import os
os.chdir("D:\Data\File")
#可视化的必要设置
%matplotlib inline
plt.rcParams["font.sans-serif"] = ["KAITI"]
plt.rcParams["axes.unicode_minus"] = False
1.1 数据集查看
#导入数据并查看前两行
df = pd.read_csv("taobao_data.txt")
df.head(5)
宝贝 | 价格 | 成交量 | 卖家 | 位置 | |
---|---|---|---|---|---|
0 | 新款中老年女装春装雪纺打底衫妈妈装夏装中袖宽松上衣中年人t恤 | 99.0 | 16647 | 夏奈凤凰旗舰店 | 江苏 |
1 | 中老年女装清凉两件套妈妈装夏装大码短袖T恤上衣雪纺衫裙裤套装 | 286.0 | 14045 | 夏洛特的文艺 | 上海 |
2 | 母亲节衣服夏季妈妈装夏装套装短袖中年人40-50岁中老年女装T恤 | 298.0 | 13458 | 云新旗舰店 | 江苏 |
3 | 母亲节衣服中老年人春装女40岁50中年妈妈装套装夏装奶奶装两件套 | 279.0 | 13340 | 韶妃旗舰店 | 浙江 |
4 | 中老年女装春夏装裤大码 中年妇女40-50岁妈妈装夏装套装七分裤 | 59.0 | 12939 | 千百奈旗舰店 | 江苏 |
1.2 修改数据类型以节省空间
# 查看数据集的数据类型、数量和内存空间
df.info(memory_usage="deep") #memory_usage参数可以查看数据集导入内存需要占用多少内存,这在导入大型数据集时非常有用
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 宝贝 100 non-null object
1 价格 100 non-null float64
2 成交量 100 non-null int64
3 卖家 100 non-null object
4 位置 100 non-null object
dtypes: float64(1), int64(1), object(3)
memory usage: 33.4 KB
df.memory_usage()
Index 128
宝贝 800
价格 200
成交量 200
卖家 800
位置 464
销售额 400
dtype: int64
df.memory_usage().sum()
2992
以上可知有五个变量,一个整型,一个浮点型,三个对象型,数据集大小是33.4KB,长度为100行;
#找出卖家这一列中名字最长的店的长度
df["卖家"].apply(lambda x:len(x)).max()
15
#查看各个变量的数据的最大值,以确定是否更改数据类型以减少占用内存
#“宝贝”这一变量的数据类型是Object,它的内容是文字,既不能转换为数值,也不能转换为类别型,只能保留其数据类型
#价格的数据类型为浮点型,最大值为698.00,保留两位小数,numpy中float有float16(半精度),float32,float64三种,半精度可以表示的最大数为65504,最小数6.104×10^(-5),所以一般情况float316就够用了
#成交量的数据类型是整型,最大值为16647,最小值为3956,所以可以转换为uint16(无符号整数(0 to 65535)
#卖家的数据类型是Object,有85个唯一值,而且长度最长有15个汉字,占30个字节,如果转换成类别型数据比Object节省空间
#位置是省级行政区,可以转换为类别型数据
df["价格"] = df["价格"].astype("float16")
df.info(memory_usage="deep") #可以看到内存减少了0.6KB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 宝贝 100 non-null object
1 价格 100 non-null float16
2 成交量 100 non-null int64
3 卖家 100 non-null object
4 位置 100 non-null object
dtypes: float16(1), int64(1), object(3)
memory usage: 32.8 KB
df["成交量"] = df["成交量"].astype("uint16")
df.info(memory_usage="deep") #可以看到内存又减少了0.6KB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 宝贝 100 non-null object
1 价格 100 non-null float16
2 成交量 100 non-null uint16
3 卖家 100 non-null object
4 位置 100 non-null object
dtypes: float16(1), object(3), uint16(1)
memory usage: 32.2 KB
df["位置"] = df["位置"].astype("category")
df.info(memory_usage="deep") #可以看到内存减少了7.3KB,减少的最多
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 宝贝 100 non-null object
1 价格 100 non-null float16
2 成交量 100 non-null uint16
3 卖家 100 non-null object
4 位置 100 non-null category
dtypes: category(1), float16(1), object(2), uint16(1)
memory usage: 24.9 KB
df["卖家"] = df["卖家"].astype("category")
df.info(memory_usage="deep") #看到内存反而升高了2.2KB,这说明Object数据类型里容纳的数据长度不齐,对短的类别少的转换为category比较有利
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 宝贝 100 non-null object
1 价格 100 non-null float16
2 成交量 100 non-null uint16
3 卖家 100 non-null category
4 位置 100 non-null category
dtypes: category(2), float16(1), object(1), uint16(1)
memory usage: 27.1 KB
df["卖家"] = df["卖家"].astype("object")
df.info(memory_usage="deep") #再转回原来的object但是内存并没有变回原来的,这有可能是没有进行压缩
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 宝贝 100 non-null object
1 价格 100 non-null float16
2 成交量 100 non-null uint16
3 卖家 100 non-null object
4 位置 100 non-null category
dtypes: category(1), float16(1), object(2), uint16(1)
memory usage: 26.6 KB
通过上述转换,从最开始的33.4KB降到26.6KB,幅度达到20%,如果是大数据集,这是惊人的效率。
1.3 查看数据集的描述性统计特征
#查看数据集的描述性统计特征,如果不指定参数,则默认只描述数值型变量,如果指定“includes=”参数,则可以看到所有数据类型的统计特征
df.describe(include="all")
宝贝 | 价格 | 成交量 | 卖家 | 位置 | |
---|---|---|---|---|---|
count | 100 | 100.000000 | 100.00000 | 100 | 100 |
unique | 99 | NaN | NaN | 85 | 8 |
top | 中老年人女装套装妈妈装夏装大码奶奶装40-50岁60短袖T恤70两件套 | NaN | NaN | 香颜旗舰店 | 江苏 |
freq | 2 | NaN | NaN | 3 | 44 |
mean | NaN | 231.669000 | 6388.93000 | NaN | NaN |
std | NaN | 130.971061 | 2770.07536 | NaN | NaN |
min | NaN | 29.000000 | 3956.00000 | NaN | NaN |
25% | NaN | 128.750000 | 4476.50000 | NaN | NaN |
50% | NaN | 198.000000 | 5314.50000 | NaN | NaN |
75% | NaN | 298.000000 | 7053.75000 | NaN | NaN |
max | NaN | 698.000000 | 16647.00000 | NaN | NaN |
#对于小数据集,还可以通过一个库统览数据集的特征———pandas_profiling;
#但是对于超过十万行的数据量该功能会占用大量内存,加载变慢
import pandas_profiling
report = pandas_profiling.ProfileReport(df)
report.to_file("census_report.html")
二、变量间关系分析及可视化描述
上面已知五个变量,两个数值型,三个文字型。先对两个数值型变量进行分析
2.1 数值型变量
#看价格的分布情况
plt.figure(figsize=(8,6),dpi=50)
sns.displot(df["价格"],bins=20)
plt.xlabel("价格")
plt.ylabel("频率",rotation=0)
plt.show()
#调整箱子,再看价格的分布情况
plt.figure(figsize=(6,4))
sns.displot(df["价格"],bins=40)
plt.xlabel("价格")
plt.ylabel("频率",rotation=0)
plt.tight_layout()
plt.show()
价格的最高在100元附近,次高在200元附近,第三高在300元附近,不是正态分布,右偏形态
#看成交量的分布
plt.figure(figsize=(10,12),dpi=100)
sns.displot(df["成交量"],bins=40,color="r")
plt.xlabel("成交量")
plt.ylabel("频率",rotation=0)
plt.show()
成交量的分布呈现指数分布
#查看价格与成交量直接是否有相关关系
plt.figure(figsize=(10,6),dpi=100)
plt.scatter(df["价格"],df["成交量"],color="r")
plt.xlabel("价格")
plt.ylabel("成交量",rotation=0)
plt.show()
从图上看相关关系好像不大,接下来计算一下协方差和相关系数
df[["价格","成交量"]].corr()
价格 | 成交量 | |
---|---|---|
价格 | 1.000000 | -0.026771 |
成交量 | -0.026771 | 1.000000 |
通过计算相关系数,也得出两者没有相关关系,并不是价格越低成交量越大
2.2 文本型变量
#查看有多少卖家,出现次数前10的卖家是哪些
len(df['卖家'].unique())
85
df[["卖家","位置"]].groupby("卖家").count().sort_values("位置",ascending=False)[:15].T
卖家 | 蒲洛妃旗舰店 | 朵莹旗舰店 | 金星靓雅服装店 | 简港旗舰店 | 香颜旗舰店 | loueddssd倍艾旗舰店 | 妃莲慕旗舰店 | 潮流前线9170 | 浅恋旗舰店 | 拓芙尼旗舰店 | 欧芮嘉旗舰店 | 梵忆轩旗舰店 | 第二号鞋铺 | 歌迪凤凰旗舰店 | 时尚_miss |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
位置 | 3 | 3 | 3 | 3 | 3 | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 1 |
df[["卖家","位置"]].groupby("卖家").count().sort_values("位置",ascending=False)[:15].plot()
df[["位置","卖家"]].groupby("位置").count().sort_values("卖家",ascending=False)[:15].T
位置 | 江苏 | 浙江 | 上海 | 湖北 | 北京 | 河北 | 广东 | 河南 |
---|---|---|---|---|---|---|---|---|
卖家 | 44 | 28 | 10 | 7 | 6 | 3 | 1 | 1 |
df[["位置","卖家"]].groupby("位置").count().sort_values("卖家",ascending=False)[:15].plot(kind="bar")
<matplotlib.axes._subplots.AxesSubplot at 0x236b48ddf60>
len(df['宝贝'].unique()) #宝贝没有重复的
99
2.3 不同变量之间的组合
#不同卖家之间成交量的对比
df[["卖家","成交量"]].groupby("卖家").mean().sort_values("成交量",ascending=False)[:10].T
卖家 | 夏奈凤凰旗舰店 | 夏洛特的文艺 | 云新旗舰店 | 韶妃旗舰店 | 千百奈旗舰店 | 依安雅旗舰店 | 千百萌旗舰店 | zxtvszml | ceo放牛 | 依诗曼妮 |
---|---|---|---|---|---|---|---|---|---|---|
成交量 | 16647.0 | 14045.0 | 13458.0 | 13340.0 | 12939.0 | 12664.0 | 12398.0 | 12087.0 | 11655.0 | 11125.0 |
df[["卖家","成交量"]].groupby("卖家").mean().sort_values("成交量",ascending=False)[:10].plot()
#不同卖家之间平均价格的对比
df[["卖家","价格"]].groupby("卖家").mean().sort_values("价格",ascending=False)[:10].T
卖家 | 简狐旗舰店 | 潮流前线9170 | 发财花旗舰店 | 歌迪凤凰旗舰店 | 蕴涵旗舰店 | 玛依恋旗舰店 | 衣之绒旗舰店 | 时尚_miss | 尼罗鹤旗舰店 | qianyaofushi888 |
---|---|---|---|---|---|---|---|---|---|---|
价格 | 698.0 | 638.0 | 558.0 | 528.0 | 498.0 | 399.0 | 399.0 | 398.0 | 398.0 | 398.0 |
df[["卖家","价格"]].groupby("卖家").mean().sort_values("价格",ascending=False)[:10].plot()
#不同位置的卖家的销量对比
df[["位置","成交量"]].groupby("位置").mean().sort_values("成交量",ascending=False)[:10].plot()
#不同位置的卖家的均价对比
df[["位置","价格"]].groupby("位置").mean().sort_values("价格",ascending=False)[:10].plot()
#新增一个销售额列,看看价格销量的变化趋势
df["销售额"] = df["价格"]* df["成交量"]/1000
cot = list(np.arange(len(df["价格"])))
plt.figure(figsize=(10,12),dpi=100)
plt.scatter(cot,df["价格"])
plt.scatter(cot,df["成交量"],c="red")
plt.scatter(cot,df["销售额"],c="orange")
plt.xlabel("卖家")
plt.ylabel("数量",rotation=0)
plt.show()
2.4 分类变量对数值型变量的影响——方差分析
from scipy import stats
df["位置"].unique()
['江苏', '上海', '浙江', '湖北', '河北', '河南', '北京', '广东']
Categories (8, object): ['江苏', '上海', '浙江', '湖北', '河北', '河南', '北京', '广东']
d1 = df[df["位置"] == "江苏"]['成交量']
d2 = df[df["位置"] == "上海"]['成交量']
d3 = df[df["位置"] == "浙江"]['成交量']
d4 = df[df["位置"] == "湖北"]['成交量']
d5 = df[df["位置"] == "河北"]['成交量']
d6 = df[df["位置"] == "河南"]['成交量']
d7 = df[df["位置"] == "北京"]['成交量']
d8 = df[df["位置"] == "广东"]['成交量']
dd=[d1,d2,d3,d4,d5,d6,d7,d8]
f,p = stats.f_oneway(*dd)
print(f,p)
0.9960034164625489 0.4393090856247839
正常情况下,可以算出F值和p值,但是在这里每个组的样本数量相差太大,因此会结果不准确
三、实际问题解决
1.哪个地方的成交量最多
2.哪个卖家成交量最多
3.哪个宝贝成交量最多
4.哪个商家的成交额最多
Most_amount = df[["位置","成交量"]].groupby("位置").sum().sort_values("成交量",ascending=False)
Most_amount[:1] #成交量最多的是江西
成交量 | |
---|---|
位置 | |
江苏 | 309360.0 |
Most_amount1 = df[["卖家","成交量"]].groupby("卖家").sum().sort_values("成交量",ascending=False)
Most_amount1[:1] #成交量最多的是简港旗舰店
成交量 | |
---|---|
卖家 | |
简港旗舰店 | 24423 |
Most_amount1 = df[["宝贝","成交量"]].groupby("宝贝").sum().sort_values("成交量",ascending=False)
Most_amount1[:1] #成交量最多的是新款中老年女装春装雪纺打底衫妈妈装夏装中袖宽松上衣中年人t恤
成交量 | |
---|---|
宝贝 | |
新款中老年女装春装雪纺打底衫妈妈装夏装中袖宽松上衣中年人t恤 | 16647 |
Most_amount1 = df[["卖家","销售额"]].groupby("卖家").sum().sort_values("销售额",ascending=False)
Most_amount1[:1] #成交量最多的是简港旗舰店
销售额 | |
---|---|
卖家 | |
潮流前线9170 | 6935.335938 |
透视表
#透视表适用于类别变量比较少的,数量太多难以透视
pt = pd.pivot_table(df,index="位置",values="成交量",aggfunc=["mean","sum"])
pt
mean | sum | |
---|---|---|
成交量 | 成交量 | |
位置 | ||
上海 | 6801.500000 | 68015 |
北京 | 4519.333333 | 27116 |
广东 | 5164.000000 | 5164 |
江苏 | 7030.909091 | 309360 |
河北 | 6050.666667 | 18152 |
河南 | 5986.000000 | 5986 |
浙江 | 5779.500000 | 161826 |
湖北 | 6182.000000 | 43274 |