数据集:Google Play Store Apps 网址:https://www.kaggle.com/lava18/google-play-store-apps?select=googleplaystore.csv
此数据集包含了两个csv文件,一个是Google play store app的整体数据,一个是Google play store用户评论的数据。
用户评论数据主观性非常大,且内容少,所以这里我们选取的是Google play store app的整体数据进行分析。
Google play store文件包含了13个字段,分别是
App: Application name(应用名称)
Category: Category the app belongs to(分类)
Rating: Overall user rating of the app (as when scraped)(评分)
Reviews: Number of user reviews for the app (as when scraped)(评论数)
Size: Size of the app (as when scraped)(大小)
Installs: Number of user downloads/installs for the app (as when scraped)(下载/安装量)
Type: Paid or Free(付费与否)
Price: Price of the app (as when scraped)(价格)
Content Rating: Age group the app is targeted at – Children / Mature 21+ / Adult(内容分级)
Genres: An app can belong to multiple genres (apart from its main category). For eg, a musical family game will belong to Music, Game, Family genres.(次分类)
Last Updated: Date when the app was last updated on Play Store (as when scraped)
Current Ver: Current version of the app available on Play Store (as when scraped)
Android Ver: Min required Android version (as when scraped)
一、导入数据
import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsdata = pd.read_csv(\'D:/Textbooks/Kaggle/Google Play Store Apps/googleplaystore.csv\')
此数据包含了10841行,13列。
data.shapeOut[291]: (10841, 13)
Rating 列的空缺值非常多,高至1474。
data.isna().sum().sort_values(ascending=False)Out[293]:Rating 1474Current Ver 8Android Ver 3Content Rating 1Type 1Last Updated 0Genres 0Price 0Installs 0Size 0Reviews 0Category 0App 0dtype: int64
二、数据清洗
因为此处不对版本和更新时间进行分析,所以首先删除掉这三列。
data.drop(columns=[\'Android Ver\',\'Current Ver\',\'Last Updated\'],inplace=True)
1. App
data[\'App\'].unique().sizeOut[295]: 9660
App在谷歌应用商店里不可以重名,这里需要删除重复值,确保分析结果准确。
data.drop_duplicates(\'App\',inplace=True)
2. Category
print(data.Category.unique())[\'ART_AND_DESIGN\' \'AUTO_AND_VEHICLES\' \'BEAUTY\' \'BOOKS_AND_REFERENCE\'\'BUSINESS\' \'COMICS\' \'COMMUNICATION\' \'DATING\' \'EDUCATION\' \'ENTERTAINMENT\'\'EVENTS\' \'FINANCE\' \'FOOD_AND_DRINK\' \'HEALTH_AND_FITNESS\' \'HOUSE_AND_HOME\'\'LIBRARIES_AND_DEMO\' \'LIFESTYLE\' \'GAME\' \'FAMILY\' \'MEDICAL\' \'SOCIAL\'\'SHOPPING\' \'PHOTOGRAPHY\' \'SPORTS\' \'TRAVEL_AND_LOCAL\' \'TOOLS\'\'PERSONALIZATION\' \'PRODUCTIVITY\' \'PARENTING\' \'WEATHER\' \'VIDEO_PLAYERS\'\'NEWS_AND_MAGAZINES\' \'MAPS_AND_NAVIGATION\' \'1.9\']
Category 有一个异常值1.9,删除。
data=data[data.Category != \'1.9\']
3. Rating
data.Rating.isna().sum()
Rating 的空缺值非常多,删除的话会缺失很多数据,但是用平均数或者中位数填充也不妥当,所以这里选择忽略na值,不做处理。
4. Reviews
转换为数值型。
data.Reviews.dtypeOut[300]: dtype(\'O\')
data.Reviews = pd.to_numeric(data.Reviews)
5. Size
data.Size.value_counts()Out[306]:Varies with device 122711M 18212M 18113M 17714M 177...226k 1903k 1190k 1400k 154k 1Name: Size, Length: 461, dtype: int64
Size数据去掉单位,统一转换成以k为单位的数值型。
def f(x):if x[-1] == \'M\':res = float(x[:-1])*1024elif x[-1] == \'k\':res = float(x[:-1])else:res = np.nanreturn resdata.Size = data.Size.apply(f)
6. Installs
data.Installs.unique()Out[308]:array([\'10,000+\', \'500,000+\', \'5,000,000+\', \'50,000,000+\', \'100,000+\',\'50,000+\', \'1,000,000+\', \'10,000,000+\', \'5,000+\', \'100,000,000+\',\'1,000,000,000+\', \'1,000+\', \'500,000,000+\', \'50+\', \'100+\', \'500+\',\'10+\', \'1+\', \'5+\', \'0+\', \'0\'], dtype=object)
去掉加号和逗号,转换为数值型。
def inst(x):if x[-1] == \'+\':res = float(x[:-1].replace(\',\',\'\'))else:res = float(x)return resdata.Installs = data.Installs.apply(inst)
7. Type
data.Type.value_counts(dropna=False)Out[313]:Free 8902Paid 756NaN 1Name: Type, dtype: int64
有一个空缺值,删除。
data.Type.dropna(inplace=True)
8. Price
将“$”符号删除,并转换为数值型。
def prc(x):if x[0] == \'$\':res = float(x[1:])else:res = float(x)return resdata.Price = data.Price.apply(prc)
9. Content Rating
data[\'Content Rating\'].value_counts()Out[318]:Everyone 7903Teen 1036Mature 17+ 393Everyone 10+ 322Adults only 18+ 3Unrated 2Name: Content Rating, dtype: int64
10. Genres
data.Genres.value_counts()Out[321]:Tools 826Entertainment 561Education 510Business 420Medical 395...Racing;Pretend Play 1Puzzle;Education 1Travel & Local;Action & Adventure 1Comics;Creativity 1Health & Fitness;Education 1Name: Genres, Length: 118, dtype: int64
多类别的数量很少,且有一个类别做分析已经足够。
为了便于分析,删除“;”后边的第二个类别。
data[\'Genres\']=data.Genres.apply(lambda x:x.split(\";\")[0])
三、数据分析
先把游戏类别筛选出来。
gamedata = data[data[\'Category\']==\'GAME\']
1.分析相关性
corrmat=gamedata.corr()plt.figure(figsize=(15,10))sns.heatmap(corrmat,annot=True,cmap=sns.diverging_palette(220, 20, as_cmap=True))
Price除了和Rating 有极小的正相关性,和其他指标都呈负相关,但是相关性都很小。
值得注意的是,上图除了Reviews和Installs存在较大的正向相关性,其他的相关性都非常小。
但是Installs和Reviews这两个指标相互影响,玩的人数越多自然评论越多。
2. 游戏类别分析和总体区别
谷歌安卓市场App一共有33个类别。
data.Category.nunique()Out[327]: 33
看看游戏类别排在第几位。
plt.figure(figsize=(20,8))fig = sns.countplot(x=data[\'Category\'], palette=\"Set3\",order = data[\'Category\'].value_counts().index)fig.set_xticklabels(fig.get_xticklabels(),rotation=90)plt.show(fig)
游戏类别的数量排在第二位!仅次于家庭类别的数量。
我们来看看各类别的安装数量。
AllInstalls = data.groupby(\'Category\')[\'Installs\'].agg(\'sum\').reset_index()AllInstalls = AllInstalls.sort_values(by=[\'Installs\'],ascending=False)
fig = plt.figure(figsize=(20,8))title=plt.title(\'Comparing all categories on the basis of Installs\')bar=sns.barplot(x=\'Category\',y=\'Installs\',data=AllInstalls)bar.set_xticklabels(bar.get_xticklabels(),rotation=90)plt.show(bar)
游戏类别排在了第一!随后是交流和工具类别,这三者的总安装量和平均安装量都是居高不下的,安卓应用市场的游戏玩家众多,下载安装量也非常之高。
那么游戏的评分和总体的评分比较是怎样的呢?
首先将游戏和总体类别的数值进行比较
data.Rating.describe()Out[335]:count 8196.000000mean 4.173243std 0.536625min 1.00000025% 4.00000050% 4.30000075% 4.500000max 5.000000Name: Rating, dtype: float64
gamedata.Rating.describe()Out[336]:count 912.000000mean 4.247368std 0.384116min 1.00000025% 4.10000050% 4.30000075% 4.500000max 5.000000Name: Rating, dtype: float64
可以看出谷歌应用商店的总体平均分高达4.17,满分是5。
但游戏的平均评分比总体的平均评分还要高,高达4.25! 且波动幅度比总体评分要小。
下面用可视化来看走势。
fig,axes = plt.subplots(figsize=(12,6),ncols=2, nrows=1)title=axes[0].set_title(\"Distribution of Rating(All App)\", y = 1.1)title=axes[1].set_title(\"Distribution of Rating(GAME)\", y = 1.1)g1 = sns.kdeplot(data.Rating, color=\'red\',shade = True,ax=axes[0])g1.set_xlabel(\"Rating\")g1.set_ylabel(\"Frequency\")g2 = sns.kdeplot(gamedata.Rating,color=\'blue\', shade = True,ax=axes[1])g2.set_xlabel(\"Rating\")g2.set_ylabel(\"Frequency\")
可以看到在高分段,游戏类别的频率是明显高于总体类别的,说明游戏类别的整体质量偏高,玩家乐于给游戏类别打高分。
下面来看看付费方式的区别。
先来看看总体商店的付费与免费App的占比。
labelall =data[\'Type\'].value_counts(sort = True).indexsizeall = data[\'Type\'].value_counts(sort = True)colors = [\"palegreen\",\"orangered\"]explode = (0.1,0) # explode 1st sliceplt.title(\'Percent of Free App in store\',size = 20)figall = plt.pie(sizeall, explode=explode, labels=labelall, colors=colors,autopct=\'%1.1f%%\', shadow=True, startangle=270)
免费游戏占了92.2%,而付费游戏仅仅占比7.8%。
下面来看看游戏类别的Type占比。
labelgame =gamedata[\'Type\'].value_counts(sort = True).indexsizegame = gamedata[\'Type\'].value_counts(sort = True)plt.title(\'Percent of Free App in game\',size = 20)figgame = plt.pie(sizegame, explode=explode, labels=labelgame, colors=colors,autopct=\'%1.1f%%\', shadow=True, startangle=270)
付费占比略微高一点,8.6%。
由此看出不管是总体还是游戏类别,免费游戏都远远大于付费游戏,比例看起来非常相似,游戏类别的付费比例要高一点点。
在游戏类别中,定价的分布是怎样的?
gameprice=gamedata[gamedata[\'Price\'] != 0.0]gpp= sns.countplot(gameprice[\'Price\'], palette = \"hls\")gpp.set_xticklabels(gpp.get_xticklabels(), rotation=90, ha=\"right\")plt.title(\'Number of apps for every price\',size = 20)
定价大都都是尾数为0.99,可以看出来厂商觉得这样更加吸引玩家购买。而其中0.99美元远超过其他定价位列第一位,其次是1.99,2.99,4.99美元。
3. 游戏的种类分析
游戏类别下划分为不同种类的游戏,我们来看看每种游戏的数量。
plt.figure(figsize=(20,5))fig = sns.countplot(x=gamedata[\'Genres\'], palette=\"Set3\",order = gamedata[\'Genres\'].value_counts().index)fig.set_xticklabels(fig.get_xticklabels(),rotation=90)plt.show(fig)
动作类、街机类、竞速类游戏分别占领游戏种类数量的前三名。
接下来看看安装量。
G_installs = gamedata.groupby(\'Genres\')[\'Installs\'].agg(\'sum\').reset_index()G_installs = G_installs.sort_values(by=[\'Installs\'],ascending=False)fig = plt.figure(figsize=(12,7))title=plt.title(\'Comparing all Genres on the basis of Installs\')bar=sns.barplot(y=G_installs[\'Genres\'],x=G_installs[\'Installs\'],palette=\'hls\')plt.show(bar)
街机游戏成为安装量最多的游戏种类。
休闲游戏的数量虽然非常少,但是安装量却排到了第三,说明玩家众多,平均下载安装量很高。随后解密类游戏、策略类游戏也都表现不错。
用可视化直观的看平均安装量。
G_installs_avg = gamedata.groupby(\'Genres\')[\'Installs\'].agg(\'mean\').reset_index( name=\'Avg_Installs\')G_installs_avg = G_installs_avg.sort_values(by=[\'Avg_Installs\'],ascending=False)fig = plt.figure(figsize=(12,7))title=plt.title(\'Comparing avg Genres on the basis of Installs\')bar=sns.barplot(y=G_installs_avg[\'Genres\'],x=G_installs_avg[\'Avg_Installs\'],palette=\'hls\')plt.show(bar)
果然没错,休闲游戏的平均安装量遥遥领先,而值得一提的是,体育类游戏的平均下载量攀升到了第二名。
那么各类型游戏的评分分布是怎么样的呢?
g = sns.catplot(x=\"Genres\",y=\"Rating\",data=gamedata, kind=\"boxen\", height = 10 ,palette = \"Set3\")g.despine(left=True)g.set_xticklabels(rotation=90)g = g.set_ylabels(\"Rating\")plt.title(\'Boxplot of Rating VS Genres\',size = 20)
解密类、运动类、休闲类游戏的评分非常稳定,也很高。
而冒险类、音乐类、竞速类等游戏评分差异比较大,平均评分也较低。
是否评分分布跟游戏类型面向的人群有关系呢?
我们可以分析一下不同类型的Content Rating。
content_G = gamedata[gamedata[\'Genres\'].isin([\'Action\',\'Arcade\',\'Racing\',\'Adventure\',\'Card\',\'Music\',\'Board\',\'Puzzle\'])]g = plt.figure(figsize=(20,5))sns.set(style=\"whitegrid\",font_scale=2,palette=\"pastel\")sns.countplot(hue=content_G[\'Content Rating\'],x=content_G[\'Genres\']);
这里综合了游戏类别的数量和平均安装量,选取了8个游戏类别进行对比。
游戏类型的Content Rating 对游戏的评分似乎没有关系。在图中,除了动作类型的游戏面向青少年的比较多以外,其他的都是面向全年龄。
4. 如何让游戏更加受欢迎
先来看看安装量最多的十款游戏。
game_sortinstalls = gamedata.sort_values(by =[\'Installs\'],ascending=False)plt.figure(figsize=(15,6))fig = sns.barplot(x=game_sortinstalls[\'App\'][:10],y=game_sortinstalls[\'Installs\'][:10],palette=\"hls\")fig.set_xticklabels(fig.get_xticklabels(),rotation=90)plt.tight_layout()plt.show(fig)
Subway Surfers成为安装量最高的游戏。
下面我想看看游戏的大小是否对游戏的安装量有影响。
游戏的Size大小各有不同,我们可以先划分为几个类别。
先来看看Size的具体情况。
gamedata.Size.describe()Out[390]:count 873.000000mean 42871.368156std 27853.882867min 116.00000025% 20480.00000050% 38912.00000075% 61440.000000max 102400.000000Name: Size, dtype: float64
最大的是102400k ,也就是100M,这是由于Google对安装包的大小上限为100M。
我们把Size划分为五个区间,每20M一个区间。
gamedata.loc[(gamedata[\'Size\'] > 0) & (gamedata[\'Size\'] <= 20480),\'Sizeval\'] = \'0M+\'gamedata.loc[(gamedata[\'Size\'] > 20480) & (gamedata[\'Size\'] <= 40960),\'Sizeval\'] = \'20M+\'gamedata.loc[(gamedata[\'Size\'] > 40960) & (gamedata[\'Size\'] <= 40960),\'Sizeval\'] = \'40M+\'gamedata.loc[(gamedata[\'Size\'] > 40960) & (gamedata[\'Size\'] <= 81920),\'Sizeval\'] = \'60M+\'gamedata.loc[(gamedata[\'Size\'] > 81920) & (gamedata[\'Size\'] <= 102400),\'Sizeval\'] = \'80M+\'
看看平均值。
gamedata[[\'Sizeval\', \'Installs\']].groupby([\'Sizeval\'],as_index=False).mean()Out[394]:Sizeval Installs0 0M+ 4.265999e+061 20M+ 9.118494e+062 60M+ 2.182831e+073 80M+ 1.829975e+07
60M-80M这个区间的平均安装量最高。
sizep = sns.barplot(x=\"Sizeval\",y=\"Installs\",data=gamedata,palette = \"Pastel1\")sizep = g.set_ylabels(\"Size\")plt.title(\'Intalls VS Size\',size = 20)
我们知道免费游戏占绝大部分的比例,安装量也最高,那么在付费游戏中,是收费越低安装量越高吗?
sns.set_style(\"darkgrid\")paidinstalls = gamedata[gamedata.Price>0]p = sns.jointplot( \"Price\", \"Installs\", paidinstalls)
猜得没错,随着价格的增多,安装量逐渐减少。大多安装量的付费游戏集中在0到4.99美元之间。
现在我们来分析一下评分,评分也是评价游戏受欢迎的一个重要因素。
sns.set_style(\"darkgrid\")ax = sns.jointplot(gamedata[\'Size\'], gamedata[\'Rating\'])
看起来影响不大,总体没有关系,只是在Size非常小的时候,评分会有极低的现象。
既然大小对评分的影响不大,那么价格是否会对评分产生影响呢?
plt.figure(figsize = (10,10))sns.regplot(x=\"Price\", y=\"Rating\", color = \'darkorange\',data=gamedata);plt.title(\'Rating and Price in Games\',size = 20)
免费游戏数量庞大,评分分化严重,随着价格的升高,评分呈上升趋势,这说明价格越高的游戏确实质量越好,而且玩家对于付费游戏的期望会比免费游戏低。
现在我们知道评分高和安装量高的游戏大概特征了,那么评分和安装量存在什么关系吗?他们之间有没有矛盾之处?还是呈正向影响?
plt.figure(figsize = (10,10))sns.regplot(x=\"Installs\", y=\"Rating\", color = \'teal\',data=gamedata);plt.title(\'Rating and Installs in Games\',size = 20)
看起来确实有一些关联!起码在比较高的安装量下,游戏的评分都不会过低,一般在4分以上。
4. 总结
1.除了安装量和评论数,各指标的相关性并不太大。
2.游戏应用是谷歌应用商店安装量最高的类别。
3.玩家对游戏的平均评价非常高,游戏的平均质量比较好。
4.付费游戏的比例很低,且游戏的定价普遍集中在0.99,1.99,2.99,4.99。
5.游戏安装量高的集中的60M-100M之间。
6.游戏的安装量和应用的大小、价格都有一定的关系,而且安装量大的游戏,评分都比较高且稳定,呈正向关系。