周末想看电影,但影评网站水军太多,如果能统计近期正在上映影片的观影人数走势图,就可以直观看出谁更具有成长性。比如口碑好,有内涵的《药神》,上映初期票房不显眼,随着口碑发酵,后期票房逐步走高。
恰好tushare
金融数据源有提供中国市场电影票房历史数据,于是就写了python程序,利用历史每日票房数据,得到了近10日观影人数走势图:
图上可以看到:
- 蜘蛛侠在上映12天后,仍然稳坐第二,后劲绵延不绝,应该能值回票价;
- 上映19天的千与千寻最近2周已表现乏力,国内重映的片子,票房通常都不太理想,家长带孩子怀旧一波自己的童年后,更多人还是更愿意在家看;
- 扫毒2在上映5天后,迎来第一个周末,冲高到400万人次,势头很猛,留待观察,如果这个周末能保持这个冲劲,就很值得一看了;
- 同样是刚上映5天的爱宠大机密2,上周末只有不到100万人次观看,如果本周还是这个数量级,说明观看人群仅限于家长陪同孩子,剧情偏向儿童,受众面较窄;
言归正传学编程
tushare
是国内爱好者为Fintech人士提供的免费金融数据源,后台数据来自交易所和新浪财经,现在演化到了pro版,接口格式主要有Python和HTTPS,详见 新版官网 和 旧版官网,本文使用的是旧版tushare
接口,官网说明摘要如下:
- 调用方法:
import tushare as ts
df = ts.day_boxoffice('2019-07-10')
- 输入参数:date,参数为空则默认取上一日
- 返回结果:
AvgPrice 平均票价
AvpPeoPle 场均人次
BoxOffice 单日票房(万)
BoxOffice_Up 环比变化 (%)
IRank 排名
MovieDay 上映天数
MovieName 影片名
SumBoxOffice 累计票房(万)
WomIndex 口碑指数
闲话少说上代码
- 首先 import tushare 包和画图的 matplotlib 包:
import tushare as ts, datetime #导入tushare包
import matplotlib.pyplot as plt #导入画图包
- 程序主框架,其中自定义函数后面会逐一介绍:
if __name__ == '__main__':
days = 10 # 经测试旧版tushare不提供早于10天的数据
# 得到最近指定天数的日期字符串列表,格式:YYYY-MM-DD
date_list = getDateList(days)
# 得到最近几天的电影票房数据,list of dataframe
movie_data_list = getMovieData(date_list)
# 返回一个可用于保存结果数据的列表,内嵌观影人数列表
result_list = constructResultList(movie_data_list)
# 汇总最近几天放映的所有电影的观影人数
result_list = countMoviePeople(movie_data_list, result_list)
# 根据最近几天所有放映电影的观影人数,绘制线图
drawLine(date_list, result_list)
- 定义函数getDateList,得到最近指定天数的日期字符串列表,日期格式YYYY-MM-DD
def getDateList(days):
# 输入参数days表示指定向前取的天数
date_list = []
for i in range(days,0,-1): #从days开始每次减1
strDate = (datetime.date.today() \
- datetime.timedelta(days=i)) \
.strftime('%Y-%m-%d')
# 日期格式:YYYY-MM-DD
date_list.append(strDate)
return date_list
# 返回列表形如['2019-06-29','2019-06-30', ...]
- 定义函数getMovieData,从tushare得到指定日期的票房数据集dataframe:
def getMovieData(date_list):
# 输入参数date_list就是最近指定天数的日期列表
movie_data_list = []
for date in date_list:
# 从tushare获取指定日期的票房 dataframe
dfMovie = ts.day_boxoffice(date)
movie_data_list.append(dfMovie)
return movie_data_list
- 定义函数constructResultList,返回一个可用于保存结果数据的列表List,其元素是字典Dict,字典第一个key-value是电影名称,第二个是观影人数列表(按日期从远到近排列),第三个是上映天数。该函数从tushare提供的dataframe列表中,统计最近几天放映的所有电影名,此时观影人数还未统计。
# 返回一个可用于保存结果数据的列表,内嵌观影人数列表
def constructResultList(movie_data_list):
result_list = []
all_movie_name_list = [] # 最近放映电影名列表
for movieData in movie_data_list:
movieNameList = movieData.MovieName
for movieName in movieNameList:
if movieName not in all_movie_name_list:
all_movie_name_list.append(movieName)
# 构造业务主键为name,内嵌观影人数列表的列表 result_list
for name in all_movie_name_list:
result_list.append({
'name': name, # 电影名称
'people': [], # 观影人数列表
'movieDay': None # 上映天数
})
# 从最近一天的票房数据dataframe中获得电影已的上映天数
movieData = movie_data_list[-1] # -1即取列表最后一个
for result in result_list:
numMovie = len(movieData.MovieName)
for i in range(numMovie):
if result['name'] == movieData.MovieName[i]:
result['movieDay'] = movieData.MovieDay[i]
return result_list
- 定义函数countMoviePeople,汇总最近几天放映的所有电影的观影人数:
# 汇总最近几天放映的所有电影的观影人数
def countMoviePeople(movie_data_list, result_list):
# 遍历最近每天的电影票房数据集 dataframe
for movieData in movie_data_list:
# 当日放映的所有电影名称列表
movieNameList = movieData.MovieName
# 单日票房(万)列表
boxOfficeList = movieData.BoxOffice
# 平均票价列表
avgPriceList = movieData.AvgPrice
# 遍历最近放映的所有电影列表
for result in result_list:
foundMovie = False # 是否当日放映了该电影
# 遍历当日放映的所有电影列表
for i in range(len(movieNameList)):
movieName = movieNameList[i]
boxOffice = boxOfficeList[i]
avgPrice = avgPriceList[i]
if result['name'] == movieName:
# 该片当日观影人数 = 当日票房 / 当日平均票价
countPeople = int(boxOffice)/int(avgPrice)
result['people'].append(int(countPeople))
foundMovie = True # 当日放映了该电影
# 当日没有放映该电影,则当日观影人数为 0
if foundMovie == False:
result['people'].append(0)
return result_list
- 定义函数drawLine,根据最近几天所有放映电影的观影人数,绘制线图
# 根据result_list保存的最近放映电影的观影人数,绘制线图
def drawLine(date_list, result_list):
# 用于正常显示中文标签
plt.rcParams['font.sans-serif']\
=['SimHei']
# 剔除日期字符串前面的4位年份和-字符
for i in range(len(date_list)):
date_list[i] = date_list[i][5:]
# 将电影已上映天数或已下映信息加到片名后面
for result in result_list:
if result['movieDay'] == None:
result['name'] += '(已下映)'
else:
result['name'] += '(上映'\
+ result['movieDay'] +'天)'
# 最近上映的每一部电影都绘制一条折线
plt.plot(date_list, result['people'],\
label=result['name'])
plt.legend() # 添加折线说明,loc默认best
plt.ylabel('观影人数次(万)')
plt.title('观影人数走势图')
plt.show()