在用LSTM做人类行为识别的时候,想用matplotlib生成概率预测的柱状图,这方面可参考的资料比较少,基本上都是在绘制折线图,不能满足要求。于是参考Matplotlib Animation Tutorial和动态排名柱状图程序,完成了分类概率输出的动态柱状图功能,现将整个流程总结如下,有相似需求的小伙伴,可以根据自己的项目要求相应修改。使用Animation类,需要安装ffmpeg或者imagemagick。win10配置ffmpeg请参考这篇文章,imagemagick直接安装即可。
第一步导入keras训练保存的模型:
from keras.models import load_model
model = load_model('my_model.h5')
第二步准备输入数据:
因为做人类行为识别,所以输入时传感器数据,因此用pandas的read_csv()方法,将UCI-HAR数据集中的.txt格式转化为pandas的DataFrame数据结构。
# 定义读取数据函数,转换为DataFrame数据结构,返回Numpy数组。
def load_file(name,filepath):
dataframe = pd.read_csv(filepath + name, header=None, delim_whitespace=True)
return dataframe.values
# 定义 pandas读取 UCI HAR 数据集中的所有数据的函数;
# 数组的维数为 [样本,时间步长,特征]([sample,timestamp,features])
# numpy 的 dstack()方法将输入数据按照第三维堆叠。
def load_group(filenames,filepath):
loaded = list()
for name in filenames:
data = load_file(name,filepath)
loaded.append(data)
# stack group so that features are the 3rd dimension
loaded = np.dstack(loaded)
return loaded
# 因为UCI-HAR数据集将六轴的传感器合三轴的重力加速度信息信息分成了九个不同的txt文本,所以需要全部导入。
# 读取数据文件所在根目录中所有文件,并将文件名添加到列表file_lists
filepath = 'D:/GraduationCode/01 Datasets/UCI HAR Dataset/test/Inertial Signals/'
y_label_path = 'D:/GraduationCode/01 Datasets/UCI HAR Dataset/test/'
file_lists = []
for parents,dirnames,filenames in os.walk(filepath):
for filename in filenames:
file_lists.append(filename)
print(file_lists)
# 加载测试集输入数据
X = load_group(file_lists,filepath)
# 加载测试集的分类标记,这个文件是1-6数字,表示六类。
y = load_file('y_test.txt',y_label_path)
# 加载测试数据集
testX, testy = X, y
print(testX.shape, testy.shape)
# 减去1以保证one-hot编码后的分类数为6
testy = testy - 1
# 使用keras的方法对分类进行one-hot编码
testy = to_categorical(testy)
print(testX.shape, testy.shape)
第三步模型预测
# predict返回每一个测试样本的各个分类概率
y_predict_list = model.predict(testX) #(2947, 6)
# 生成分类标签
y_pred = model.predict_classes(testX) #(2947, 1)
#转换为DataFrame
df_pred_pro = pd.DataFrame(y_predict_list)
# 修改列标题
df_pred_pro.rename(columns={0:'Walking',1:'Walking-upstairs',2:'Walking-downstairs',3:'Sitting',4:'Standing',5:'Laying'},inplace=True)
df_pred_pro
最终输出
第四步绘制动态柱状图:
from matplotlib.animation import FuncAnimation
#保证动图以弹出显示,后端为qt5
#%matplotlib qt5
import time
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False
plugins = ['Walking','Walking-upstairs','Walking-downstairs','Sitting','Standing','Laying']
fig, ax = plt.subplots(figsize=(20,8))
# 分配颜色的字典
# enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
colormap = [i / len(plugins) * 0.7 + 0.15 for i, _ in enumerate(plugins)]
colormap = plt.get_cmap('Paired')(colormap)
plugin_color = {plugins[i]: colormap[i] for i in range(len(plugins))}
frame = 20
# 设置更新函数,i为帧的ID,这样就能一帧一帧的更新图像。
def update(i):
print(i)
df_ = df_pred_pro
names = df_.iloc[i,:].index
colors = [plugin_color[name] for name in names]
value = df_.iloc[i,:].values
ax.clear()
rects = ax.bar(x=names,height=value,width=0.8,align='center',color=colors)
# 设置y轴刻度
ax.set_yticks(np.arange(0,1.1,0.05))
# 添加x、y轴描述信息和标题
ax.set_xlabel('预测类别',color='black',size=15)
ax.set_ylabel('概率', color='black',size=15)
ax.set_title('模型概率预测 timestamp:{}'.format(i*64),color='blue',size=20)
# 添加网格显示
ax.grid(linestyle='--',alpha=0.5)
# 每个柱的数字标签
for i_, v in enumerate(value):
ax.text(i_-0.06, v + 0.02, '%.5f%%'%(v*100), color=colors[i_])
#ax.text(3, 1.1, 128+i_*64, fontweight='bold', fontsize='25', color='red')
return rects
ani = FuncAnimation(fig=fig, # 更新的画布
func=update, # 更新函数
frames=1000, # 生成动态图的帧数
interval=100, # 帧间时间间隔,单位:ms
blit=True, # 让输出显示更快
repeat=False # 不循环播放
)
ani.save('test.mp4', # 文件名称
fps=10, #保存的视频帧率
extra_args=['-vcodec', 'libx264']) # x264解码规则,以支持HTML5视频格式。
# ani.save('test.gif', writer='ffmpeg')
# %matplotlib in line
# from IPython.display import HTML
# HTML(ani.to_html5_video())
#plt.show()
保存的视频:
视频在这:LSTM人类行为识别动态概率输出柱状图