09可视化深度探索苹果AppStores

导入库

import pandas as pd
import numpy as np

from matplotlib import pyplot as plt
import seaborn as sns

import plotly_express as px
import plotly.graph_objects as go

数据基本信息

data = pd.read_csv("AppleStore.csv", index_col=0)
data.head()
image.png
# 整体大小
data.shape
image.png
# 缺失值
data.isnull().sum()
image.png
# 字段类型
data.dtypes
image.png
# 描述信息
data.describe()
image.png

APP信息统计

# 免费的APP数量
sum(data.price==0)
image.png
# 价格超过50$的APP数量,价格大于50$即表示为:超贵
sum(data.price >= 50)
image.png
# 价格超过50$的比例
sum((data.price > 50) / len(data.price) * 100)
image.png
sum(data.price >= 50) / len(data) * 100
image.png
# 立群数据
# 价格超过50$的APP信息
outlier = data[data.price > 50][["track_name", "price", "prime_genre", "user_rating"]]
outlier
image.png

免费APP

freeapps = data[data["price"] == 0]
freeapps.head()
image.png

正常区间的APP

# 取数
paidapps = data[(data["price"] > 0) & (data.price < 50)]
print("max_price:", max(paidapps.price))
print("min_price:", min(paidapps.price))
image.png
# 价格分布
plt.style.use("fivethirtyeight")
plt.figure(figsize=(12, 10))

# 绘制直方图
plt.subplot(2, 1, 1)
plt.hist(paidapps.price, log=True)
# 标题和label值
plt.title("Price distribution of apps (Log scale)")
plt.ylabel("Frequency Log scale")
plt.xlabel("Price Distributions in ($)")

# 绘制stripplot(分布散点图)
plt.subplot(2, 1, 2)
plt.title("Visual Price distribution")
sns.stripplot(data=paidapps, 
              x="price", 
              jitter=True,  #当数据点重合较多时,用该参数做调整 
              size=6)

plt.show()
image.png

1.随着价格的上涨,付费应用的数量呈现指数级的下降
2.很少应用的价格超过30刀;因此,尽量保持价格在30以下

category对价格分布的影响

data.columns
image.png
# 种类及数目
data["prime_genre"].value_counts()
image.png
# 显示前5个种类
yrange = [0, 25]
fsize = 15
plt.figure(figsize=(12, 10))

plt.subplot(5, 1, 1)
plt.xlim(yrange)
games = paidapps[paidapps["prime_genre"] == "Games"]
sns.stripplot(data=games,
             x="price",
             jitter=True,
             size=6,
             color="#eb5e66")
plt.title("Games", fontsize=fsize)
plt.xlabel("")


plt.subplot(5, 1, 2)
plt.xlim(yrange)
ent = paidapps[paidapps["prime_genre"] == "Entertainment"]
sns.stripplot(data=ent,
             x="price",
             jitter=True,
             size=6,
             color="#ff8300")
plt.title("Entertainment", fontsize=fsize)
plt.xlabel("")

plt.subplot(5, 1, 3)
plt.xlim(yrange)
edu = paidapps[paidapps.prime_genre == "Education"]
sns.stripplot(data=edu,
              x="price",
              jitter=True,
              size=6,
              color="#20B2AA")
plt.title("Education", fontsize=fsize)
plt.xlabel("")

plt.subplot(5, 1, 4)
plt.xlim(yrange)
pv = paidapps[paidapps.prime_genre == "Photo & Video"]
sns.stripplot(data=pv,
              x="price",
              jitter=True,
              size=6,
              color="#b84efd")
plt.title("Photo & Video", fontsize=fsize)
plt.xlabel("")

plt.subplot(5, 1, 5)
plt.xlim(yrange)
ut = paidapps[paidapps.prime_genre == "Utilities"]
sns.stripplot(data=pv,
              x="price",
              jitter=True,
              size=6,
              color="#084cfd")
plt.title("Utilities", fontsize=fsize)
plt.xlabel("")
image.png

1.Games游戏类的apps价格相对高且分布更广,直到25美元
2.Entertainment娱乐类的apps价格相对较低

Paid apps Vs Free apps

# 付费APP和免费APPA之间的比较
# app的种类
categories = data["prime_genre"].value_counts()
categories
image.png
len(categories)
image.png
# 选择前4个
s = categories.index[:4]
s
image.png
def categ(x):
    if x in s:
        return x
    else:
        return "Others"
    
data["broad_genre"] = data["prime_genre"].apply(categ)
data.head()
image.png
# 统计免费和付费APP下的种类数
# 免费
data[data.price==0].broad_genre.value_counts()
image.png
# 免费APP
free = data[data.price==0].broad_genre.value_counts().sort_index().to_frame()
free
image.png
# 付费
paid = data[data.price > 0].broad_genre.value_counts().sort_index().to_frame()
paid
image.png
# 全部
total = data.broad_genre.value_counts().sort_index().to_frame()
total
image.png
# 将两个数据合并起来
free.columns = ["free"]
paid.columns = ["paid"]
total.columns = ["total"]

free
image.png
# 统计量对比
dist = free.join(paid).join(total)
# 另一种写法
dist = pd.concat([paid, free, total], axis=1)
dist
image.png
# 生成比例
dist["paid_per"] = dist.paid / dist.total * 100
dist["free_per"] = dist.free / dist.total * 100
dist
image.png
# 高亮显示最大值
dist.style.highlight_max()
image.png

1.Games相关的APP是最多的,不管是paid还是free
2.从付费占比来看,Education教育类型占比最大
3.从免费占比来看,Entertainment娱乐类型的占比最大

付费和免费的占比

# 生成数据
# 分组对比付费和免费的占比
list_free = dist.free_per.tolist()
list_free
image.png
# 列表转成元组
tuple_free = tuple(list_free)
tuple_paidapps = tuple(dist.paid_per.tolist())
# 柱状图
plt.figure(figsize=(12, 8))
N = 5
ind = np.arange(N)
width = 0.56 #两个柱子间的宽度

p1 = plt.bar(ind, tuple_free, width, color="#45cea2")
p2 = plt.bar(ind, tuple_paidapps, width, bottom=tuple_free, color="#fdd400")

plt.xticks(ind, tuple(dist.index.tolist()))
plt.legend((p1[0], p2[0]), ("free", "paid"))
plt.show()
image.png
# 饼图
pies = dist[["free_per", "paid_per"]]
pies.columns = ["free %", "paid %"]
pies
image.png
plt.figure(figsize=(15, 8))

pies.T.plot.pie(subplots=True,  #显示子图
               figsize=(20, 4),  #大小
               colors=["#45cea2", "#fad470"])  #颜色

plt.show()
image.png

1.在教育类的APP中,付费paid的占比是很高的
2.相反的,在娱乐类的APP中,免费free的占比是很高的

付费APP真的足够好吗?

# 价格分类
data["category"] = data["price"].apply(lambda x: "Paid" if x > 0 else "Free")
data.head()
image.png
# 小提琴图
plt.figure(figsize=(15, 8))
plt.style.use("fast")
plt.ylim([0, 5])

plt.title("Distribution of User ratings")

sns.violinplot(data=data,
              y="user_rating",
              x="broad_genre",
              hue="category",
              vertical=True,  #垂直显示
              kde=False,
              split=True,  #同个类别的小提琴图一起显示
              linewidth=2,
              scale="count",
              palette=["#fdd470", "#45cea2"])

plt.xlabel(" ")
plt.ylabel("Rating(0-5)")

plt.show()
image.png

1.在Education类的APP中,paid的占比是明显高于free;其次是Photo & Video
2.Entertainment娱乐的APP,free占比高于paid;且整体的占比分布更为宽

plt.figure(figsize=(15, 8))
plt.style.use("fast")
plt.ylim([0, 5])

plt.title("Distribution of User ratings")

sns.violinplot(data=data,
              y="user_rating",
              x="broad_genre",
              hue="category",
              vertical=True,  #垂直显示
              kde=False,
              split=False,  #同个类别的小提琴图一起显示
              linewidth=2,
              scale="count",
              palette=["#fdd470", "#45cea2"])

plt.xlabel(" ")
plt.ylabel("Rating(0-5)")

plt.show()
image.png

size和price关系

sns.color_palette("husl", 8)
sns.set_style("whitegrid")

flatui = ["#9b59b6", "#3498db", "#95a5a6", "#e74c3c", "#34495e", "#2ecc71"]

data["MB"] = data.size_bytes.apply(lambda x: x/1048576)
# 挑选区间的数据
paidapps_regression = data[((data.price < 30) & (data.price > 0))]

sns.lmplot(data=paidapps_regression, 
          x="MB",
          y="price",
          height=4,
          aspect=2,
          col_wrap=2,
          hue="broad_genre",
          col="broad_genre",
          fit_reg=False,
          palette=sns.color_palette("husl", 5))

plt.show()
image.png
# 使用Plotly实现
px.scatter(paidapps_regression,
          x="MB",
          y="price",
          color="broad_genre",
          facet_col="broad_genre",
          facet_col_wrap=2)
image.png
# APP分类:是否可根据paid和free来划分
# 5种类型对比

# 设置颜色和大小
BlueOrangeWapang = ["#fc910d", "#fcb13e", "#239cd3", "#1674b1", "#ed6d50"]
plt.figure(figsize=(10, 10))
# 数据
label_names = data.broad_genre.value_counts().sort_index().index
size = data.broad_genre.value_counts().sort_index().tolist()
# 内嵌空白圈
my_circle = plt.Circle((0, 0), 0.5, color="white")
# 圆
plt.pie(size, labels=label_names, colors=BlueOrangeWapang)
p = plt.gcf()
p.gca().add_artist(my_circle)
plt.show()
image.png
# 使用Plotly实现
fig = px.pie(values=size,
            names=label_names,
            labels=label_names,
            hole=0.5)

fig.update_traces(textposition="inside", textinfo="percent+label")
fig.show()
image.png
# 5种类型+是否付费
f = pd.DataFrame(index=np.arange(0, 10, 2),
                data=dist.free.values,
                columns=["num"])
p = pd.DataFrame(index=np.arange(1, 11, 2),
                data=dist.paid.values,
                columns=["num"])

final = pd.concat([f, p], names=["labels"]).sort_index()
final
image.png
final.num.tolist()
image.png
plt.figure(figsize=(20, 20))

group_names = data.broad_genre.value_counts().sort_index().index
group_size = data.broad_genre.value_counts().sort_index().tolist()
h = ["Free", "Paid"]

subgroup_names = 5*h
sub = ["#45cea2", "#fdd470"]
subcolors = 5*sub
subgroup_size = final.num.tolist()

# 外层
fig, ax = plt.subplots()
ax.axis("equal")
mypie, _ = ax.pie(group_size, radius=2.5, labels=group_names, colors=BlueOrangeWapang)
plt.setp(mypie, width=1.2, edgecolor="white")

# 内层
mypie2, _ = ax.pie(subgroup_size, radius=1.6, labels=subgroup_names, labeldistance=0.7, colors=subcolors)
plt.margins(0, 0)

plt.show()
image.png
# 使用Plotly实现
fig = px.sunburst(data,
                 path=["broad_genre", "category"],
                 values="MB")

fig.show()
image.png

来源:尤而小屋

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容