Python数据可视化-支付宝蚂蚁森林能量收取记录

支付宝蚂蚁森林模块最早从2016年推出,题主最开始从支付宝集福活动开始接触。期间懒懒散散收过一些能量,但是相比朋友圈动辄几十几百公斤的能量值,我的能量值只有20Kg,想种棵胡杨连零头都不够。所以,本着节流开源的想法,题目决定利用Python分析一下,平时自己的能量都去哪了。

1、获取蚂蚁森林的收取记录

由于蚂蚁森林的收取记录只在手机App上显示,所以想要获得还得想些办法。经过一番查找,决定使用AutoJs,这是一个使用JS来进行自动化测试的软件。截止现在,免费版的Android版本在酷安软件市场已经下载不到了,题主的是之前安装的版本4.0.1。

但是目前支付宝版本升级之后,现有代码基本失效,有能力的童鞋可以自行修改,运行之后会在目录下生成recordEnergy.txt。我使用的是19年4月份抓取的数据记录,共抓取了49天的数据。

JS代码分析

收取记录的页面是一直可以往下翻的,加载时间约为0.5秒。所以写一个循环,一直翻页就好了。

auto()
toast("开始测试")

var isDown = true
for(var i=0; i<85; i++){
    if(isDown){     
        sleep(random(3,6)*1000)
        getInfo()
        isDown = scrollDown()
        log("动一下--》"+i)
    } 

    else{
        log("滑动失败")
        sleep(100)
        scrollUp()
        sleep(100)
        isDown = scrollDown()
        sleep(random(3,6)*1000)
        log("尝试滑动一下-----》"+i)
    }
}

将获取到的记录信息写入文件:日期及时间、姓名、操作种类及能量数目。

function intoFile(information){
    files.append("recordEnergy.txt", information+"\n")
}

主要获取信息的函数,遍历所有子控件,如果控件可见,就获取信息,也是为了避免重复抓取。

function getInfo(){
// 获取可见控件的信息
    var first = className("android.webkit.WebView").findOnce()
    var second = first.child(0).child(0).children()
    second.forEach(
        function(childPara){
            if(childPara.visibleToUser() == true){ 
                if(childPara.childCount() == 0){
                    var dayStr = childPara.contentDescription
                    log(dayStr)
                }
                else{
                    var timeStr = childPara.child(3).contentDescription
                    var nameStr = childPara.child(2).child(0).contentDescription
                    var numStr = childPara.child(2).child(1).contentDescription 
                    var info = timeStr+"\t"+nameStr+"\t"+numStr+"\t"+dayStr
                    intoFile(info)
                }
            }
        }
    )
}

2、对原始数据进行清洗

对抓取到的.txt文件进行简单处理,这里题主使用的Excel。文件的信息有4类,其中对于姓名一栏,抓取的是人物昵称,需要一一核对替换;操作使用的是Excel的分列操作,当然直接使用正则表达式进行提取也是可以的;数量一栏,是以克为单位,没什么好说的;日期一栏是直接抓取的格式,后面会进行处理。另存为蚂蚁森林收取记录.csv文件即可。

姓名 操作 数量 日期
果子 帮忙收取/浇水/收取 12 2019/4/19 19:06

3、Python绘图展示

这里是本次的重点,使用的Python包为Numpy、Pandas、Matplotlib、Seaborn,请自行安装。下面开始介绍代码主体。
首先导入此次的包文件及一些设置

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# 显示中文和负号,务必确保安装了黑体的字体
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
# 一些matplotlib画图的设置
large = 16; med = 12; small = 10
params = {'axes.titlesize': large,
          'legend.fontsize': med,
          'figure.figsize': (9, 6),
          'axes.labelsize': large,
          'axes.titlesize': med,
          'xtick.labelsize': med,
          'ytick.labelsize': med,
          'figure.titlesize': large}
plt.rcParams.update(params)
# 设置使用漫画绘图模式,禁用可以返回普通模式
plt.xkcd()

a、数据格式处理

代码如下,都是一些pandas的基础操作,没什么好讲的。

origindData = pd.read_csv("蚂蚁森林收取记录.csv", encoding="gbk")
# 提取别人收取能量的记录
recordData = origindData[origindData["操作"]=="收取"]
# 重置索引
recordData.reset_index(drop=True, inplace=True)
# 转换日期格式
recordData['time'] = pd.to_datetime(recordData['时间'],infer_datetime_format=True)

对于人名,题主决定采用名称的缩写,保护一下别人的隐私。

# xpinyin这个python包
from xpinyin import Pinyin
p = Pinyin()
# 转换拼音
recordData["name"] = recordData["姓名"].apply(lambda x : p.get_initials(x, ""))

b、绘制收取能量的排行图

首先获取排行排名的数据

# 数据聚合
sumSeries = recordData.groupby("name")["数量"].sum()
# 将聚合的结果转换为dataframe
sumData = pd.DataFrame({"name": sumSeries.index, "count":sumSeries.values})
# 排序
sumData.sort_values("count", ascending=False, inplace=True)
# 重置索引
sumData.reset_index(drop=True, inplace=True)

然后对sumData绘图

fig, ax = plt.subplots()
# 共画15个
for i in range(15):
    # 制定颜色
    color = plt.cm.tab10_r(sumData.loc[i, "count"]/550)
    # 画排行的竖直线
    ax.vlines(sumData.loc[i, "name"], 0, sumData.loc[i, "count"], color=color, linewidth=2)
    # 画竖直线上面的球
    ax.scatter(sumData.loc[i, "name"], sumData.loc[i, "count"], color=color, s=50)
    # 标注文字
    ax.text(sumData.loc[i, "name"], sumData.loc[i, "count"]+15, color=color, s=str(sumData.loc[i, "count"]), fontsize=11, horizontalalignment='center', verticalalignment='bottom')

# 设置x坐标范围
ax.set_ylim(0,600)
# 设置标签
ax.set_xlabel("Short Name")
ax.set_ylabel("Number of Energy/g")
# ax.set_title("蚂蚁森林能量收取排行榜前15", size=20, loc="center")
# 设置坐表轴隐藏
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

# 保存图像
plt.savefig("XKCD-能量收取排行前15.png", dpi=300)

结果

蚂蚁森林能量收取排行前15.jpg

c、绘制每天各时段能量被收取的序列图

画主体图形
首先准备数据

# 将时间格式里面的小时和分钟,计算成分钟数
recordData["timeSeries"] = recordData["time"].apply(lambda x: x.hour*60+x.minute)

# 创建每半个小时的时间分箱数据
# 创建分箱的标签范围
def getTimeLabels(x=0,y=24,step=1):
    timeLabels = []
    for i in range(x,y,step):
        for j in [":00", ":30"]:
                  timeLabels.append(str(i)+j)
    return timeLabels
# 分箱的数值范围
timeBins = np.linspace(0, 1440, 49)
# 分箱的标签范围
timeLabels = getTimeLabels()
# 分箱操作
recordData["timeBins"] = pd.cut(recordData["timeSeries"], bins=timeBins, labels=timeLabels)
# 进行聚合操作
tempData = recordData.groupby("timeBins")["数量"].sum()
# 将结果转换为dataframe
recordBinsData = pd.DataFrame({"time":tempData.index, "number":tempData.values})

绘制图形

fig, ax = plt.subplots()
# 绘制所有时段的
for i in (recordBinsData.index):
    # 产生颜色
    color = plt.cm.tab10_r(recordBinsData.loc[i, "number"]/310)
    # 画竖直线
    ax.vlines(i, 0, recordBinsData.loc[i, "number"], color=color, linewidth=3)
    # 画柱子上的球
    ax.scatter(i, recordBinsData.loc[i, "number"], color=color, s=3)

# 设置坐标轴
ax.set_xlim(0, len(recordBinsData))
ax.set_ylim(0,1400)
# 设置Y轴刻度间隔
ax.yaxis.set_minor_locator(plt.MultipleLocator(100))
# 设置X轴间隔为1
ax.xaxis.set_minor_locator(plt.MultipleLocator(1))
# 设置X轴标签
plt.xticks( np.arange(0, 48, 5), recordBinsData[::5]["time"] )
# 设置坐表轴隐藏
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
# 设置网格线
ax.grid(alpha=0.1)
# 设置标签
ax.set_xlabel("Time")
ax.set_ylabel("Number of Energy/g")

添加子图操作

# 创建1分钟的分箱结果
# 创建分箱的标签范围
def getTimeLabels(x=7,step=1):
    timeLabels = []
    for j in range(0,60,step):
        timeLabels.append(str(x)+":"+str(j))
    return timeLabels

# 分箱的数值范围
timeSmallBins = np.arange(420, 481)
# 分箱的标签范围
timeSambllLabels = getTimeLabels()
# 分箱操作
recordData["timeSmallBins"] = pd.cut(recordData["timeSeries"], bins=timeSmallBins, labels=timeSambllLabels)
# 进行聚合操作
tempData = recordData.groupby("timeSmallBins")["数量"].sum()
recordSmallBinsData = pd.DataFrame({"time":tempData.index, "number":tempData.values})

绘制图形

# 添加子图
ax1 = fig.add_axes([0.5, 0.4, 0.4, 0.4])
# 添加图形
ax1.plot(recordSmallBinsData.index, recordSmallBinsData["number"], color="darkred", linewidth=1)
# 充填直线的颜色
plt.fill_between(np.arange(0,31), 0, 650, color="red", alpha=0.05)
plt.fill_between(np.arange(30,61), 0, 650, color="blue", alpha=0.05)

# 设置坐标轴
ax1.set_xlim(0,60)
ax1.set_ylim(0,250)
# 设置X轴间隔为1
ax1.xaxis.set_minor_locator(plt.MultipleLocator(2))
# 设置X轴标签
plt.xticks( np.arange(0, 61, 10), recordSmallBinsData[::10]["time"] )
# 设置标签
ax1.set_xlabel("Time", fontsize=med-1)
ax1.set_ylabel("Number of Energy/g", fontsize=med-1)
# 设置坐表轴隐藏
ax1.spines['right'].set_color('none')
ax1.spines['top'].set_color('none')
# 设置网格线
ax1.grid(alpha=0.1)
# ax.set_title("蚂蚁森林森林能量每天时段收取统计", size=20, loc="center")

# 保存图像
plt.savefig("XKCD-蚂蚁森林森林能量每天平均收取统计.png", dpi=300)

结果


蚂蚁森林森林能量每天平均收取统计.jpg

d、绘制这49天来的每天被收取能量的记录

首先获取数据

# 处理得到日期
recordData["date"] = recordData["time"].apply(lambda x : x.strftime("%Y-%m-%d"))
# 聚合操作
tempData = recordData.groupby("date")["数量"].sum()
# 将结果整理成dataframe操作
dateData = pd.DataFrame({"date":tempData.index, "number":tempData.values})

绘制折线图

fig, ax = plt.subplots()
# 画折线图
ax.plot(dateData.index, dateData["number"], color="darkred" , alpha=0.7, linewidth=1.5)
# 填充颜色
plt.fill_between(np.arange(0,27), 0, 350, color="green", alpha=0.04)
# 设置X轴坐标
ax.set_xlim(0, len(dateData))
ax.set_ylim(0, 350)
# 设置X轴间隔为1
ax.xaxis.set_minor_locator(plt.MultipleLocator(2))
# 设置X轴刻度
plt.xticks(np.arange(len(dateData)+1)[::12], [dateData.loc[x, "date"] for x in range(0, len(dateData), 12)])
# 设置标签
ax.set_xlabel("Date")
ax.set_ylabel("Number of Energy/g")
# 设置坐表轴隐藏
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
# 设置网格
ax.grid(alpha=0.1)
# ax.set_title("蚂蚁森林森林能量每天收取统计", size=20, loc="center")

# 保存图像
plt.savefig("XKCD-蚂蚁森林森林能量每天收取统计.png", dpi=300)

结果


蚂蚁森林森林能量每天收取统计.jpg

4、结果简单分析

a、从第一张排行图可以看出,能量收取最多的克数成阶梯状分布,以500、400、300、200左右具有台阶。这个分布并不是预想的顺滑下降;
b、从第2张每天的时段序列图可以看出,每天的7-8点、1-2点以及晚上的7-8点半是收取能量的高峰,基本都是吃完以后的休息时间啊。能量收取最多的时间段为早上的7点-8点,高峰开始的时间为7:28左右,别人都是早起收能量的啊;
c、最后一张日期分布图,左边阴影部分是假期时间,左边的峰值与低谷与右边的具有明显区别,看来假期和在校的日常活动不再同一个水平啊。

所以最后要想收集能量多,还是早点起床收能量吧,哈哈。

最后,转载请注明出处!!!

你可能感兴趣的:(Python数据可视化-支付宝蚂蚁森林能量收取记录)