前言:在小组老师的领导下,我开始学习数据可视化分析,学着做项目,老师给了我一个月的时间来做,我会一周写一次实战总结。主要记载实战过程中遇到的问题和解决办法
python版本:3.7
matplotlib版本:3.3.2
pandas版本:1.1.2
numpy版本:1.19.2
1.我在网上找了数据,但它是txt格式的,我需要转换成csv格式,代码如下
import csv
txt_list = []
with open('数据/数据.txt', 'r', encoding='utf-8') as filein:
for line in filein:
line_list = line.strip('\n').split('\t') # 我这里的数据之间是以 tab 间隔的
txt_list.append(line_list)
# csv_writer.writerow(line_list)
with open('数据/数据.csv', 'w', newline='', encoding='utf-8-sig') as csvfile:
csv_writer = csv.writer(csvfile)
head = ["序号", "电影名", "导演", "主演", "上映时间", "国家", "电影类型", "评分", "播放量", "主要内容", "链接"]
csv_writer.writerow(head)
for row in txt_list:
row_list = row[0].split(',')
csv_writer.writerow(row_list)
数据是网上找的,转换代码也是网上的,但是有错,这是我改后的代码。
附上数据链接:https://blog.csdn.net/qq_41479464/article/details/97019057
2.csv文件读取到pandas后行列显示不全,解决办法如下
# 显示所有列
pd.set_option('display.max_columns', None)
# 显示所有行
pd.set_option('display.max_rows', None)
我的导入包是
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
3.需求一:分析各个国家的电影的上映量占比,并以饼图方式展现。那么如何能够按照各个国家对电影上映量求总和呢,经过上网搜索,我发现了pandas透视表是个好东西,代码如下:
movie_country = movie_df.pivot_table(index=["国家"], values=["电影名"], aggfunc=len)
上面这行代码实现创造一个以index为分组依据,求电影名的总数的透视表
这里附上我收藏的一篇比较好的pandas透视表的讲解链接https://www.cnblogs.com/onemorepoint/p/8425300.html
movie_df来自这里:
head = ["序号", "电影名", "上映时间", "国家", "电影类型", "评分", "播放量"]
movie_df = pd.read_csv("数据/数据.csv", index_col=False, usecols=lambda x: x in head)
index_col意思是不让我的第一列作为dataframe的行号,usecols是为了添加每一列的标题
然后我想求每个国家上映量的占比,代码如下:
movie_country.eval('国家占比=电影名/250', inplace=True)
这行代码给movie_country这个数据框添加了一个“国家占比”的一列,这列的值=电影名/250
4.绘制饼图时由于变量太多,加上有些只占到4%导致数据重合,解决办法:
plt.pie(movie_country["国家占比"], # 每个饼块的实际数据,如果大于1,会进行归一化,计算percentage
explode=explode_list, # 每个饼块离中心的距离
colors=colors_list, # 每个饼块的颜色
labels=country_list, # 每个饼块的标签
labeldistance=None, # 每个饼块标签到中心的距离
autopct='%1.1f%%', # 百分比的显示格式
pctdistance=1.1, # 百分比到中心的距离
shadow=True, # 每个饼块是否显示阴影
startangle=0, # 默认从x轴正半轴逆时针起
radius=3.8, # 饼块的半径
textprops={'fontsize': 8}, # 字体大小
)
在这里面有个参数是explode,我们让相近值的饼块离中心的距离不同就行了
我的explode_list值如下:
explode_list = [0.0]*22
explode_list[16] = 0.1
explode_list[19] = 0.3
explode_list[18] = 0.4
explode_list[15] = 0.2
explode_list[14] = 0.3
explode_list[13] = 0.4
展示图例代码:
plt.legend(loc='upper right')
显示效果如下:
5.需求二:分析各国家电影的平均观看量和平均评分,并以双y轴柱状图的形式展现。通过透视表我想要的数据得到了,但是一般播放量都是整数,并且平均评分太长,我想让它保留3位小数,解决代码如下:
movie_country = movie_df.pivot_table(index=["国家"], values=["播放量", "评分"])
movie_country['播放量'] = movie_country['播放量'].astype("int")
movie_country['评分'] = movie_country['评分'].round(3)
我想像饼图那样,加上数据显示,代码如下:
for x, y in enumerate(movie_country['评分'].values):
plt.text(x-0.5, y, "%s" % y, fontsize=6)
然后我想实现双y轴画法,这个比较麻烦,网上的也很少,好在最终还是找到了解决办法:
plt1 = plt.bar(x=country_list, height=movie_country["评分"], width=-0.4, align='edge', color='y', label='电影平均评分')
ax2 = plt.twinx()
plt2 = ax2.bar(x=country_list, height=movie_country["播放量"], width=0.4, align='edge', label='电影平均播放量')
关键在于plt.twinx()函数,这个函数实现了让ax2共享plt的x轴
显示效果如下:
6.需求三:分析各年段电影上映数量并绘制直方图,我首先面临的问题是怎样获得各年段,pandas中没有一个比较方便的函数能直接达到这个目的,我只能自己编写函数:
def search_year(x):
"""根据上映时间确定属于哪个年代段"""
if 1930 <= x < 1940:
return '1930'
elif 1940 <= x < 1950:
return '1940'
elif 1950 <= x < 1960:
return '1950'
elif 1960 <= x < 1970:
return '1960'
elif 1970 <= x < 1980:
return '1970'
elif 1980 <= x < 1990:
return '1980'
elif 1990 <= x < 2000:
return '1990'
elif 2000 <= x < 2010:
return '2000'
elif 2010 <= x < 2020:
return '2010'
movie_df['年代段'] = movie_df['上映时间'].apply(func=search_year)
创建一个新的名为"年代段"列,它里面的值是把movie_df[‘上映时间’]传到search_year()函数 返回的结果
然后我就跟据这个列创建了一个透视表,接着就开始画图,然后我发现x轴的年代不连续,并且显示不全,解决代码如下:
year_list = [1930, 1940, 1950, 1960, 1970, 1980, 1990, 2000, 2010, 2020]
movie_df.sort_values('上映时间', inplace=True)
max_year = max(year_list)
min_year = min(year_list)
plt.hist(movie_df['上映时间'], bins=range(min_year, max_year+10, 10))
plt.xticks(year_list, rotation=45, fontsize=10)
这里要注意,直方图的x轴只接受整型,plt.hist()的第一个参数是数据,第二个参数是为了解决画图没有对齐刻度的问题,个人理解它是条形的左边刻度。plt.xticks()函数可以调整x轴
加网格代码:
plt.grid(True, linestyle='--', alpha=0.4)
画布调整代码:
plt.figure(figsize=(6.4, 5.0))
展示效果如下: