暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何更优雅地可视化决策树续:完美中文支持

alitrack 2021-08-06
2285

自从知道了如何更优雅地可视化决策树 后,发现中文支持很差,就一直避免使用中文,最近的项目不得不输出中文,于是下决心解决掉它。

dtreeviz[1] 基于 matplotlib, 网上关于 matplotlib 中文支持的方案很多,但没有一个能解决问题, 认真查看代码后,发现需要同时从两方面下手,

  • 修改 matplotlib 的配置
  • 修改 dtreeviz 的底层代码

修改 dtreeviz 底层代码实现中文支持

修改 matplotlib 的配置只能部分解决乱码问题,于是需要从底层代码来解决这个问题。

dtreeviz 在trees.py
classifiers.py
使用了默认字体Arial
, 我通过简单修改, 允许配置默认的字体。先附上简单的代码实现。

utils.py
添加一个变量,

import matplotlib.pyplot as pltdefault_font=plt.rcParams['font.sans-serif'][0]

这样只需要修改 matplotlib 默认字体就可以达到中文的完美支持(当然日语韩语也不是问题,只要有合适的字体),修改后的代码我放在了https://github.com/alitrack/dtreeviz

修改 matplotlib 默认字体

下面这段代码要优先执行

default_font = 'Arial Unicode MS'from matplotlib import pyplot as pltplt.rcParams['font.sans-serif']=[default_font]+plt.rcParams['font.sans-serif']plt.rcParams['axes.unicode_minus']=False # 确保正常显示减号➖

这样做的好处,是它这是当前环境下修改了 matplotlib 配置,并不会影响别的程序。

不建议修改配置文件(对于 seaborn,即使修改配置文件也没有用),可能影响别的程序。

测试效果

from sklearn.datasets import *from sklearn import treefrom dtreeviz.trees import *classifier = tree.DecisionTreeClassifier(max_depth=3)iris = load_iris()classifier.fit(iris.data, iris.target)#测试需要feature_names=['萼片sepal length (cm)','sepal width (cm)','花瓣petal length (cm)','花瓣petal width (cm)']class_names=["山鸢尾 (부채붓꽃)""变色鸢尾(ブルーフラッグ)""维吉尼亚鸢尾(Iris-virginica)"]## 画决策树viz = dtreeviz(classifier,               iris.data,               iris.target,               target_name='variety',               feature_names=feature_names,               class_names=class_names  # need class_names for classifier              )viz

输出

中日韩都不是问题?

如果你的系统没有中文字体,或者没有你想要的中文字体咋办?下面就介绍下如何给 matplotlib 安装中文字体。

给 matplotlib 安装中文字体

对于 macOS 和 Linux 可以使用下面两种方式来判断是否有你想要的字体

fc-list :lang=zh

或者

font_manager.fontManager.ttflist

会返回系统安装的字体以及字体所对应的字体名
(不同于字体文件名)

<Font 'Arial Unicode MS' (Arial Unicode.ttf) normal normal 400 normal>,

判断 matplotlib 默认字体及安装路径

通过下面命令,可以得知 matplotlib 的默认字体是DejaVuSans.ttf
,默认安装路径(具体看你的 Python 虚拟环境安装位置)是,

/Users/steven/anaconda3/envs/py39/lib/python3.9/site-packages/matplotlib/mpl-data/fonts/ttf/
from matplotlib import pyplot as pltplt.rcdefaults() # 恢复到初始化设置from matplotlib.font_manager import findfont, FontPropertiesfindfont(FontProperties(family=FontProperties().get_family()))

返回

'/Users/steven/anaconda3/envs/py39/lib/python3.9/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'

下载与安装字体

  • 下载想要的字体

比如 SimHei(simhei.ttf), Arial Unicode MS(Arial Unicode.ttf)

  • 下载安装

下载好的字体 copy 到对应的目录,

cp simhei.ttf /Users/steven/anaconda3/envs/py39/lib/python3.9/site-packages/matplotlib/mpl-data/fonts/ttf/
  • 清除 matplotlib 缓存
rm -rf ~/.matplotlib
  • reset 当前 notebook(如果是在 notebook 里)

seaborn 的中文支持

seaborn 也是基于 matplotlib, 它的中文支持更加方便,但网上的方案基本都有问题

import seaborn as snsfrom matplotlib import pyplot as pltiris = sns.load_dataset('iris')iris.columns=['萼片sepal_length''萼片sepal_width''花瓣petal_length''花瓣petal_width',       'species']iris.replace(["setosa","versicolor","virginica"],           ["山鸢尾 (부채붓꽃)""变色鸢尾(ブルーフラッグ)""维吉尼亚鸢尾(Iris-virginica)"],           inplace=True)# sns.set_style("whitegrid",{"font.sans-serif":plt.rcParams['font.sans-serif']})# style used as a theme of graph# for example if we want black# graph with grid then write "darkgrid"sns.set_style("whitegrid")#set_style 会 override plt.rcParams['font.serif'],我们再override回来plt.rcParams['font.sans-serif']=[default_font]+plt.rcParams['font.sans-serif']plt.rcParams['axes.unicode_minus']=False # 让负号也能正常显示sns.pairplot(iris, hue="species")

输出

sns.set_style("whitegrid")
会覆盖 matplotlib 的默认字体设置,

这里可以做个简单的验证,

default_font="Arial Unicode MS"
plt.rcdefaults()
print("matplotlib默认:",plt.rcParams['font.sans-serif'])
sns.set_style('darkgrid')
print("被seaborn修改后:",plt.rcParams['font.sans-serif'])
plt.rcParams['font.sans-serif']=[default_font]+plt.rcParams['font.sans-serif']
print("再改回来:",plt.rcParams['font.sans-serif'])

而我们要做就是在这个代码之后,改为我们希望的字体即可。

plt.rcParams['font.sans-serif']=[default_font]+plt.rcParams['font.sans-serif']

从上面 dtreeviz 和 seaborn 来看,关键是看字体配置啥时候被修改,记得改回来,使用你希望的字体。

字体资源

Google Noto Fonts[2]

Google 开源的字体,Noto
no more tofu 的缩写(别再显示豆腐块,就是那种无法显示的字体以方块形式出现,像豆腐),noto-cjk
的 GitHub 网址是https://github.com/googlefonts/noto-cjk。

其它的网上自己搜索吧。

参考资料

[1]

dtreeviz: https://github.com/alitrack/dtreeviz

[2]

Google Noto Fonts: https://www.google.com/get/noto/


文章转载自alitrack,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论