Scikit-learn: 添加 sklearn.plot 模块

创建于 2019-03-14  ·  60评论  ·  资料来源: scikit-learn/scikit-learn

以下是迄今为止与绘图相关的工作概述:

为了帮助控制sklearn.plot ,我建议我们只在轴级别而不是图形级别进行绘图。 用户将轴作为关键字传递。 为方便起见, axes的默认值为None 。 只有在这种情况下,绘图函数才会生成要在其上绘图的轴/图形。

所有60条评论

由于根据小胶质打开这个问题,平安@jnothman @amueller @GaelVaroquaux

8425 与分类器的决策区域无关,?

我更喜欢将 plot_tree 和 plot_partial_dependence 移动到 sklearn.plot 并在 0.21 中解决 #13335(可能会引入一个函数来绘制决策边界,因为它对初学者来说很重要而且不容易 IMO)。 其他人怎么看?

为了帮助控制 sklearn.plot 的范围,我建议我们只在轴级别而不是图形级别进行绘图。 用户将轴作为关键字传递。 为方便起见,轴的默认值将为无。 只有在这种情况下,绘图函数才会生成要在其上绘图的轴/图形。

好主意,但与现有函数(plot_tree 和 plot_partial_dependence)不一致,对吗?

在某些情况下,您需要输出/修改图形,例如
多个子图(参见 seaborn 的分面图等,以及
例子)。 你能给出你想把它限制在轴上的原因吗?

2019 年 3 月 15 日星期五凌晨 2:19 秦汉敏, [email protected]写道:

感谢您打开这个问题,ping @jnothman
https://github.com/jnothman @amueller https://github.com/amueller
@GaelVaroquaux https://github.com/GaelVaroquaux根据 gitter

8425 https://github.com/scikit-learn/scikit-learn/issues/8425不是

与分类器的决策区域有关,?
我更喜欢将 plot_tree 和 plot_partial_dependence 移动到 sklearn.plot 和
解决 #13335 https://github.com/scikit-learn/scikit-learn/issues/13335
在 0.21 中(也许引入一个函数来绘制决策边界,因为
对于初学者 IMO 来说,这很重要且不容易)。 其他人怎么看?

为了帮助控制sklearn.plot的范围,我建议我们只做绘图
在轴级别而不是图形级别。 用户将传入轴
作为关键字。 为方便起见,轴的默认值将为无。 只有在
在这种情况下,绘图函数是否会生成要绘制的轴/图形。

好主意,但与现有函数(plot_tree 和
plot_partial_dependence),对吧?


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/scikit-learn/scikit-learn/issues/13448#issuecomment-472914237
或静音线程
https://github.com/notifications/unsubscribe-auth/AAEz6y4ZcL4WftNY92wCoz19vqtXL9Njks5vWmiCgaJpZM4b0Oiz
.

好主意,但与现有函数(plot_tree 和 plot_partial_dependence)不一致,对吗?

@qinhanmin2014 plot_tree好像没有调整数字。 plot_partial_dependence确实根据features制作了多个图。 虽然,它可以重构为轴级别图。 用户需要多次调用plot_partial_dependence给它不同的轴(和功能)。

你能给出你想把它限制在轴上的原因吗?

@jnothman Seaborn 的文档清楚地将“图形级”绘图和“轴级”绘图区分开来。 如果我们能在 scikit-learn 中正确地记录这种行为,就有可能得到这些“图形级”的图。 我对“图形级”图的最大担忧是它们更难维护和测试。 一个轴上的元素可能会与另一个轴重叠。 尽管如此,我们可以通过以不经常发生重叠的方式构建图形来解决这个问题。

在测试方面,我们可以采用seaborn的方式直接测试matplotlib对象,或者采用yellowbrick的方式进行像素级测试。 我倾向于测试 matplotlib 对象。

我的 2 美分:

  • +1 用于包含访问公共子包中的 matplotlib 的函数,或者在每个子包(sklearn.linear_models.plot、sklearn.ensemble.plot)中的模块上。

  • 正如@thomasjpfan所提到的,只有访问轴才能更容易测试。

    此外,很久以前,生态系统中曾讨论过为其他绘图后端提供一个类似“Axes”的对象以实现兼容性。 我不知道那去了哪里。 快速谷歌搜索并没有显示太多。 最接近的是 plotly.tools.mpl_to_plotly,它并不真正需要这个限制,所以我认为这个论点是徒劳的。

也许引入一个函数来绘制决策边界,因为它对初学者来说很重要而且不容易 IMO

我同意,但我也认为向用户展示如何绘制决策边界等结果是示例的目标之一。

如果我想快速绘制第一张结果图,绘图函数非常有用,尤其是对于绘制树等复杂图,但我经常喜欢根据需要调整图,因此我更喜欢依赖现有示例和修改代码。

关于模块的名称,IMO inspectplot更通用:

  • 我想不出任何不是某种检查的情节
  • #12599(部分依赖)已经引入了inspect

IMO检查比情节更通用

没有强烈的意见,将为两个名字投票+1。 也许情节更直接?

我再次对在 0.21 之前创建新模块感兴趣,并将 plot_tree 和 plot_partial_dependence 移到那里。 理想情况下,我们还应该就 API 达成共识(例如,轴级别/图形级别)。

支持inspect其他观点:

我们可能需要提供绘图作为选项的检查工具。 例如,打印一棵树的特征(节点数、叶子数、分裂点数等),并可选择使用 matplotlib 绘制它。


我会赞成使用轴而不是数字,如建议的那样(叹气,我需要再次更改 PDP)。 我们更容易支持和测试。 这对用户来说需要更多的工作,但它也允许更多的控制。

IMO检查比情节更通用

没有强烈的意见,将为两个名字投票+1。 也许情节更直接?

“检查”在 Python 中加载(它是标准库中的一个模块)。 一世
将避免使用相同的名称。

我再次对在 0.21 之前创建新模块感兴趣,并将 plot_tree 和 plot_partial_dependence 移到那里。 理想情况下,我们还应该就 API 达成共识(例如,轴级别/图形级别)。

这不应该延迟 0.21。 我们的目标是尽早发布,并希望
再次提前发布。

“检查”在 Python 中加载(它是标准库中的一个模块)。 一世
将避免使用相同的名称。

我建议model_inspection 。 它与我们的model_selection名称很相配。

我们可能想要检查一些不是模型的东西(编码器、预处理器、网格搜索结果......)

inspection然后呢?

那些东西也是模型:)

Gael 对每个子包上的公共情节子模块的建议是值得的
考虑。

FWIW,我也更喜欢plotinspect ,因为大多数用户找到它更直观。 人们更有可能尝试_绘制_他们的模型而不是_检查_他们的模型(例如,在搜索引擎上搜索时,或查看其 IDE 上可能的自动完成选项时)。

Gael 对每个子包上的公共情节子模块的建议值得考虑。

如果是这样,我们应该把plot_decision_boundary放在哪里?

关于#12599, @NicolasHug我怀疑partial_dependence是否应该在新模块中。 (即,ensemble.partial_dependence + plot.plot_partial_dependence)

如果是这样,我们应该把 plot_decision_boundary 放在哪里?

sklearn.plot ?

我不想为这个解决方案太用力。 不过,我同意
最终用户可能更容易发现“情节”的感觉。

关于#12599, @NicolasHug我怀疑partial_dependence 是否应该在新模块中。 (即,ensemble.partial_dependence + plot.plot_partial_dependence)

我不明白你的意思。 #12599 弃用ensemble.partial_dependence而支持inspect.partial_dependence (当然inspect可能会根据此讨论进行更改)。 两种实现的 API 也不同。


我对plot很好,我只是担心与最终检查模块的潜在高度重叠,但我不会进一步推动它:)

每个子包上的公共绘图子模块值得考虑。

但到目前为止,所有提出的绘图工具(PDP、校准、混淆矩阵和决策区域)都不是特定于单个模块的。

我不明白你的意思。 #12599 弃用 ensemble.partial_dependence 支持inspect.partial_dependence(当然,inspect 可能会根据此讨论进行更改)。 两种实现的 API 也不同。

抱歉,我没有详细查看那个 PR。 也许inspect.partial_dependence + plot.plot_partial_dependence

也许inspect.partial_dependence + plot.plot_partial_dependence?

我喜欢计算值和绘制它之间的明确分离。
这是一个类似于分离的模型/视图,它应该有助于增加
可重用性。

Gaël 不是早先提出 sklearn.inspect.partial_dependence 吗?
sklearn.inspect.plot.plot_partial_dependence(替换一些其他名称
适当时进行检查)? 我不介意这个。

Gaël 不是早先提出 sklearn.inspect.partial_dependence 和 sklearn.inspect.plot.plot_partial_dependence (如果合适,用其他名称代替检查)?

是的,但我问他我们应该把plot_decision_boundary放在哪里,他似乎改变了主意?

仅供参考,我按照上述建议更新了 PDP PR https://github.com/scikit-learn/scikit-learn/pull/12599

  • partial_dependence位于sklearn.model_inspection
  • plot_partial_dependence位于skearn.plot

文档在这里https://53182-843222-gh.circle-artifacts.com/0/doc/_changed.html

请注意,用户指南目前仅包含plot模块。 我认为有一个只讨论model_inspection.partial_dependence的用户指南部分是没有意义的,因为它的约束/行为与plot_partial_dependence约束/行为相同。

(这是我担心的那种重叠)

当然,如果您认为为partial_dependenceplot_partial_dependence提供单独的用户指南仍然更好,我会这样做。

仅供参考,我按照上述建议更新了 PDP PR #12599:
partial_dependence 在 sklearn.model_inspection
plot_partial_dependence 在 skearn.plot

+1

请注意,用户指南目前仅包含绘图模块。 我认为有一个只讨论 model_inspection.partial_dependence 的用户指南部分是没有意义的,因为它的约束/行为与 plot_partial_dependence 的约束/行为相同。

+1

所以我们决定使用 sklearn.plot 这个名字?

当我们避免将每个人都放在根命名空间中时,我发现 sklearn.plot 从跨 sklearn 导入依赖项有点奇怪。

所以你更喜欢sklearn.model_inspection.plot并将plot_partial_dependence()放在那里?

没有plot模块,我很好

我想我更喜欢那个。 尚不确定它是如何概括的。

我想我更喜欢那个。 尚不确定它是如何概括的。

只要我们能找到一个合适的地方来放置plot_decision_boundary ,我就会为sklearn.XXX.plot投+1 票。

这需要睡觉吗? 我们似乎没有取得太大进展

编辑呃,困了我读了乔尔的评论,因为认为我更喜欢那个,对不起

这需要睡觉吗? 我们似乎没有取得太大进展

我对任一解决方案都满意( sklearn.plot / sklearn.XXX.plot )。 IMO 的主要问题是,如果我们使用sklearn.XXX.plot ,没有人告诉我应该把plot_decision_boundary类的东西放在哪里:)

sklearn.model_inspection.plot ?

sklearn.model_inspection.plot?

有趣的想法,我会投+1。 也许把所有的东西都扔到 sklearn.plot 不太好(https://github.com/rasbt/mlxtend 把所有的绘图功能放在一个模块中)。

所以我们会支持from sklearn.XXX.plot import plot_XXX吗? 我们会支持from sklearn.XXX import plot_XXX吗?

我认为 .plot 在导入中的明确要求是什么
其他人在这里寻求。

还有从 sklearn.plot.XXX import plot_YYY 反转

我认为 .plot 在导入中的明确要求是这里其他人所寻求的。

所以我们已经达成共识使用sklearn.XXX.plot (仅支持 from sklearn.XXX.plot import plot_XXX )?

还有从 sklearn.plot.XXX import plot_YYY 反转

我无法理解。

还有从 sklearn.plot.XXX import plot_YYY 反转

我的意思是我们可以有
sklearn.plot.model_inspection.plot_partial_dependence 而不是
sklearn.model_inspection.plot.plot_partial_dependence。 不确定这是否
提供任何好处/清晰度。

我的意思是我们可以有
sklearn.plot.model_inspection.plot_partial_dependence 而不是
sklearn.model_inspection.plot.plot_partial_dependence。 不确定这是否
提供任何好处/清晰度。

所以现在我们有3个选择:
(1) sklearn.plot.plot_YYY(例如,sklearn.plot.plot_tree)
(2) sklearn.plot.XXX.plot_YYY(例如,sklearn.plot.tree.plot_tree)
(3) sklearn.XXX.plot.plot_YYY(例如sklearn.tree.plot.plot_tree,不支持从sklearn.XXX import plot_YYY)
我将为所有这些解决方案投 +1 票。
我更喜欢在 0.21 之前做出决定以避免弃用 sklearn.tree.plot_tree

不确定它是否需要睡觉,但可能值得邀请对它的意见
邮件列表

不确定它是否需要睡眠,但可能值得在邮件列表中征求意见

+1。 它似乎不属于 SLEP 的标准。

正如我在邮件列表中所说,我认为我们真的还应该考虑“工作在哪里进行”或界面会是什么样子。 对于部分依赖,这已经很不清楚了。
plot_partial_dependence调用partial_dependence还是将partial_dependence的输出作为输入? 这个问题对于基本上所有的绘图函数都是一个有效的问题。
我与@NicolasHug讨论的主要考虑是让plot_X调用compute_X对用户来说很方便 - 只要他们只想绘制一次。 如果他们不喜欢情节并想改变一些东西,他们需要再次compute_X ,这可能是一种浪费。

所以我们可以

  • 始终采用compute_X 。 缺点:不方便且容易出错:precision_recall_curve 中的精度、召回率和阈值的顺序是什么?
  • 总是将输入带到compute_X并从plot_X调用compute_X plot_X 。 缺点:您需要为每个情节重新计算。

  • 允许两者都允许,所以plot_X可以接受compute_X的输入并调用compute_X或者如果用户已经创建了compute_X的输出。 这具有使签名复杂化的缺点(并且可能使记录它变得复杂)。 此外,如果用户调用plot_X以便它在内部执行compute_X然后想要另一个情节,她需要再次compute_X 。 因此,在第一次调用plot_X之前,您需要预测您需要多个绘图。 或者你需要在调用plot_X compute_X时暴露

  • 根据计算_X 的成本做出决定,至于混淆矩阵、部分依赖图和校准图,我们不关心重新计算的成本,但对于部分依赖图,我们会关心。 缺点:接口不一致。

我与@NicolasHug讨论的主要考虑是让 plot_X 调用 compute_X 对用户来说很方便 - 只要他们只想绘制一次。 如果他们不喜欢情节并想要更改某些内容,他们需要再次计算_X,这可能是一种浪费。

+1000。 这是我在研究代码中看到的一个常见问题。

从设计问题来看,它违反了 MVC 分离(有点迂腐,
对不起)。

在您提出的各种解决方案中,您是否会考虑采取
拟合模型作为一种方法? 我觉得这会减轻
记住参数的顺序。 但也许还有额外的
问题。

我不确定你说的拟合模型是什么意思。 通常计算的输出不是拟合模型。 我们可以为所有计算结果定义对象,以便partial_dependence返回一个PartialDependence对象。 或者一堆。 但它不会返回一个估算器。

哦,我现在提出这个的原因:如果没有这个决定,我不知道用户代码会是什么样子,而且我不喜欢在无法写下示例的情况下做出命名/API 决定;)

返回一个对象将非常类似于 sklearn,恕我直言。 但它可能会解决位置问题:它可能有一个plot方法;)

通常计算的输出不是拟合模型。 我们可以为所有计算结果定义对象,以便 partial_dependence 返回一个 PartialDependence 对象。 或者一堆。 但它不会返回一个估算器。

取点。

一种选择(不是说它是最好的)是拥有所有
计算函数返回命名元组和所有相应的计算
函数采取这个。 会有点符合现代
对 Python 标准库的补充。

我不喜欢在无法写下示例的情况下做出命名/API 决策;)

我像你。

所以如果计算很昂贵,我们可以在函数之外进行计算。 如果是这样,我们返回一个对象,绘图函数将此对象作为其输入,对吗? 我会投+1。

也许我们需要另一个问题来讨论这个:)

@GaelVaroquaux的建议的好处是它可能不需要用户因为元组解包而更改他们的代码。 但是如果像confusion_matrix那样有一个返回的对象,那将不起作用。 元组不是绝对必要的,但接口变得稍微不一致。

@qinhanmin2014如果我们返回任意对象,我们必须在每次创建绘图助手时弃用函数的返回类型。 这似乎是一团糟。

我有一个想法,然后是第二个更好的想法:
1) 创建第二个面向对象的接口,该接口调用现有函数、存储对象并具有 plot 方法,例如

cm = ConfusionMatrix(y, y_pred)
cm.plot()

这将解决问题,但会重复一些界面,而且会有点不清楚。 其实同样的原理可以用我认为更直观的方式来完成:
2) 让plot_函数总是做这项工作,使用结果来实例化一个存储结果的对象并绘制它:

plot_confusion_matrix(y, y_pred)

因此只需绘制并返回一个ConfusionMatrixPlotter对象,该对象存储结果,并具有plot方法。
所以在只绘制一次的简单情况下,它只是一个函数调用。 如果您希望结果用它做其他事情,它们将存储在对象中。 如果你想再次绘图,你可以再次在对象上调用plot 。 如果您已经计算了结果,然后决定要绘图,则可以直接实例化ConfusionMatrixPlotter

虽然这为更复杂的用例公开了一个额外的类,但我认为这是一个合理的权衡,因为它对所有情况都有很好的答案。

因此只是绘图,并返回一个 ConfusionMatrixPlotter 对象,该对象存储结果,并具有绘图方法。

为什么用户需要再次绘制相同的数据? @amueller调整格式?

@qinhanmin2014是的,把字体变大,改变颜色,在同一个图中与其他东西一起绘制,添加标签,......

@qinhanmin2014是的,把字体变大,改变颜色,在同一个图中与其他东西一起绘制,添加标签,......

我怀疑在这里考虑这些格式问题是否值得。 用户可以开始将数据集的一小部分吗?

@amueller我们将支持传递轴,以便用户在调用绘图函数后可以轻松调整绘图?

@qinhanmin2014不,很多事情事后不能轻易改变,我们不需要自己考虑所有的格式,但我们应该让用户重新绘制一些东西。 基本上任何时候你做一个情节都会发生。 每次我想做一个绘图时都必须对数据集进行二次采样有点烦人。 如果我以后改变主意,我仍然需要重新计算。
基本上,关键是您通常无法在探索性分析中准确预测您想要什么,并且必须重新计算所有内容以更改可视化效果似乎并不好。

@qinhanmin2014不,很多事情事后不能轻易改变,我们不需要自己考虑所有的格式,但我们应该让用户重新绘制一些东西。 基本上任何时候你做一个情节都会发生。 每次我想做一个绘图时都必须对数据集进行二次采样有点烦人。 如果我以后改变主意,我仍然需要重新计算。

是的,我知道它可能很有用,但这里的主要问题是我们没有一种干净的方法来支持此功能,而且我猜大多数绘图功能不需要太多计算?

我喜欢我们在讨论这个问题时更接地气,但我是
仍然不完全相信我们甚至需要在导入中包含情节
路径。 毕竟,我们似乎有 plot_ 作为前缀
职能。 这个问题也与 plot_tree 有关:为什么这样
与其他导出和文本可视化代码分开?

@qinhanmin2014我不认为“我们还没有好的 API”是一个很好的理由。
而 GridSearchCV 和 RandomizedSearchCV 的部分依赖、排列重要性、学习曲线、验证曲线和结果都是需要大量计算的常见示例。 尽管对于 gridsearchcv 和 randomsearchcv 显而易见的事情是传递对象或cv_results_ ,但在这些情况下在绘图函数内部进行工作似乎是荒谬的。 我不完全确定学习曲线和验证曲线 tbh。

@jnothman我认为@GaelVaroquaux想要将 matplotlib 依赖限制在一个模块中,这是主要动机之一吗? 我对此还没有非常一致的想法。

而 GridSearchCV 和 RandomizedSearchCV 的部分依赖、排列重要性、学习曲线、验证曲线和结果都是需要大量计算的常见示例。

谢谢,我现在意识到我错了:)
虽然我仍然无法理解为什么为用户提供一种无需重新计算的绘图方法很重要。 但如果其他人这么认为并且有一个好方法,我会投 +1 票。

我喜欢我们在讨论这个问题时更接地气,但我是
仍然不完全相信我们甚至需要在导入中包含情节
路径。 毕竟,我们似乎有 plot_ 作为前缀
职能。 这个问题也与 plot_tree 有关:为什么这样
与其他导出和文本可视化代码分开?

是的,这也可以是一种选择。 如果是这样,我们可以提到所有以plot_开头的函数都需要 matplotlib。 此选项的另一个优点是我们不需要移动现有功能。

回顾这个讨论,我同意添加sklearn.plot模块,并使用前缀plot_来表示matplotlib要求。

例如,在https://github.com/scikit-learn/scikit-learn/pull/12599 中partial_dependenceplot_partial_dependence将被放置在inspection

好的,除非有人在接下来的几天内不同意这一点,否则我将更新 PDP PR 并且:

  • partial_dependenceplot_partial_dependence放入sklearn.inspection
  • make plot_partial_dependencefigax对象作为属性返回一堆(现在它以元组形式返回它们)。 这样,当我们从https://github.com/scikit-learn/scikit-learn/issues/13448#issuecomment -479512520 实现第二个选项时,我们将能够保持这两个函数向后兼容

我们可以在这里做最后的决定吗?
@jnothman@NicolasHug和我同意的提案(如果我错了,请道歉):sklearn.XXX.plot_YYY(来自 sklearn.XXX import plot_YYY 的支持)。 我们会提到所有以 plot_ 开头的函数都需要 matplotlib。
这个提议的一个主要优点是我们不需要移动现有的功能。

睡在它上面我认为解释起来很简单,它避免了在不同模块之间考虑共享绘图 api 的困难。

是的,让我们这样做。 制作一个辅助函数以提供更有用的
导入错误

仅供参考,我在 #12599 中添加了sklearn.utils.check_matplotlib_support

def check_matplotlib_support(caller_name):
    try:
        import matplotlib
    except ImportError as e:
        raise ImportError(
            "{} requires matplotlib. You can install matplotlib with "
            "`pip install matplotlib`".format(caller_name)
        ) from e

仅供参考,我在 #12599 中添加了 sklearn.utils.check_matplotlib_support

那太棒了! 谢谢。

此页面是否有帮助?
0 / 5 - 0 等级