TowardsDataScience 2023 博客中文翻译(一百三十三)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

二月刊:聊聊聊天机器人

原文:towardsdatascience.com/february-edition-lets-talk-about-the-chatbot-cf65fba75078?source=collection_archive---------13-----------------------#2023-02-02

月刊

(是的,你知道的那一个)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 TDS Editors

·

关注 发表在 数据科学之道 ·3 分钟阅读·2023 年 2 月 2 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Fleur 提供,来自 Unsplash

自 OpenAI 推出 ChatGPT 以来的两个月中,这里有一件事我们可能都能达成共识:这真的是很多

自从聊天机器人出现以来,我们 TDS 的情况如何?感谢你的提问!想象一下过山车,设在镜子迷宫中,灯光闪烁:这大致可以给你一个从编辑角度看待的体验。

我们从未见过单一话题能以如此强烈的程度吸引我们社区的集体关注,看到读者和作者因这一工具的潜力而充满活力令人兴奋。看到被炒作的文章(我们没有发布)以及我们审核队列被 AI 生成的文章堵塞(据我们所知,我们也没有发布那些文章),则令人沮丧。

就像我们在Medium的朋友们一样,他们最近反思了他们关于 ChatGPT 及类似工具的政策,我们也花时间讨论了聊天机器人的影响。结果,我们更新了我们的指南,并明确表示我们只接受完全由人类撰写的文章。

在这段时间里,幸运的是,我们的作者继续利用他们的专业知识分享有关这一新兴技术的智能、审慎和及时的文章。为了庆祝他们出色的写作帮助读者以更全面、更有见地的视角看待 ChatGPT,我们挑选了一些最有力的贡献。(如果你发现了其他你喜欢的文章,欢迎在评论中分享链接。)

一如既往,感谢你花时间阅读我们发布的内容。如果你想以更直接的方式支持我们(同时访问我们的整个档案),请考虑成为 Medium 会员

TDS 编辑

TDS 编辑亮点

  • ChatGPT 是如何工作的:机器人背后的模型(2023 年 1 月,8 分钟)

    如果你需要对 ChatGPT 的工作方法和技术基础设施有一个清晰易懂的介绍,Molly Ruby的解释是必读之作。

  • ChatGPT 的碳足迹(2022 年 12 月,7 分钟)

    在 ChatGPT 发布后的几天内,Kasper Groes Albin Ludvigsen试图回答关于该模型环境影响的关键问题。

  • 并非全是彩虹和阳光:ChatGPT 的黑暗面(2023 年 1 月,9 分钟)

    除了大型语言模型的有趣和创意方面,Mary Reagan 博士认为我们应当至少同样关注潜在的风险和伦理问题。

  • 微软与谷歌:语言模型会超越搜索引擎吗? (2023 年 1 月,12 分钟)

    ChatGPT 将如何改变我们的在线习惯和工作流程?展望(可能不久的)未来,Alberto Romero 反思了大型语言模型与传统网页搜索之间的激烈竞争。

  • ChatGPT 能写出比数据分析师更好的 SQL 吗? (2023 年 1 月,6 分钟)

    Marie Truong的文章(我们 1 月份阅读量最高的文章!)探讨了一个显然在许多数据专业人士心中的问题:机器是否最终会让我们变得多余?

热门文章

如果你错过了,以下是上个月在 TDS 上最受欢迎的一些文章。

  • 区分高级开发者与初级开发者的 5 个 Python 技巧 作者:Tomer Gabay

  • 2023 年从数据分析师跃升为数据科学家的途径 作者:Mary Newhauser

  • 最常用的 7 种特征工程技术 作者:Dominik Polzer

  • 2023 年现代数据堆栈的未来 作者:Prukalpa 和 Christine Garcia

  • Pandas 与 Polars:语法与速度比较 作者:Leonie Monigatti

  • 初学者应避免的 4 个常见 Python 错误 作者:Murtaza Ali

由于一批令人印象深刻的新 TDS 作者,我们今年有了一个非常强劲的开局——请与我们一起欢迎Jonah BreslowTaylor WagnerErtuğrul DemirAkshay DagarWill BadrFrauke AlbrechtChad IsenbergStefany GoradiaAleksandra MaBoris RufGalen OkazakiAlle SravaniHerman MichaelsJazmia HenryTrevor CoppinsMartin LeitnerJacky KaubShenyang(Andy) HuangChristoph MöhlKatherine MunroSebastian CharmotMiriam SantosTin NguyenAmogh VaishampayanMurat UnalEbrahim PichkaJohn MorrowOded MousaiChristopher McDonaldBárbara BarbosaJonathan BogerdJonas DieckmannAlejandro Correa BahnsenPushpak PujariMatthew HarrisTomáš NeubauerMaggie HaysVino DuraisamyIstván MódosLukáš ZahradníkMary Reagan PhDChristian Koch、和Bale Chen等。如果你有有趣的项目或想法要与我们分享,我们非常乐意听取你的意见!

下月见。

2023 年女子世界杯通过 Plotly 可视化

原文:towardsdatascience.com/fifa-womens-world-cup-2023-visualized-with-plotly-a7277edf6278

数据科学家的五个图表评论

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Caroline Arnold

·发布于 Towards Data Science ·阅读时间 5 分钟 ·2023 年 8 月 22 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Your Lifestyle Business 提供,来源于 Unsplash

2023 年 7 月和 8 月,澳大利亚和新西兰联合举办了 FIFA 女子世界杯。共有 32 个国家队参赛,西班牙首次赢得冠军。重大体育赛事总是产生大量数据,我借此机会学习如何使用 Plotly。

Plotly 是一个开源图表库,用于创建交互式图表。它可以离线或在线使用,并与多种编程语言集成。我使用 Python,因为我对它最为熟悉,并创建静态图表。代码可以在 GitHub 上找到。

在五个数据故事中,我们将尝试不同的 Plotly 功能,并展示世界杯历史和今年比赛的一些有趣事实:

  1. 历史世界杯参赛情况

  2. 球员年龄与比赛表现

  3. 球员的俱乐部

  4. 送出最多活跃球员的国家

  5. 男子和女子世界杯奖金对比

1: 女子世界杯参赛情况

历史上,许多国家曾禁止女性踢足球。德国足球协会(DFB)在 1955 年决定,“缺乏优雅可能会损害女性脆弱的身体和灵魂,并会对道德和社会造成攻击”。直到 1970 年,禁令才被解除。今天,女性在全球范围内踢足球,只有少数国家仍有限制。

我们的第一个数据故事以条形图形式展示了各国女子足球队在世界杯中的参赛情况。自 1991 年首次举办以来,这项赛事已举行九次。来自每个大陆的国家都有参与。其中一些国家每届世界杯都参赛,而另一些仅参赛过一次。我很惊讶地发现朝鲜竟然参加了四次!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

各国世界杯参赛情况。数据:维基百科。图片:作者。

这是生成静态条形图的代码。为了容纳众多条目,图例从默认的右侧位置移动到图表顶部。

2: 球队年龄和表现

国家队名单在维基百科上是公开的。我们展示了国家队球员的年龄分布图。颜色代码表示球队在比赛中的排名。据我所见,并没有明显的模式——各类中位年龄的球队进入淘汰赛阶段的机会相似。海地和赞比亚以非常年轻的阵容脱颖而出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

国家队球员的年龄。数据:维基百科。图片:作者。

为了生成这个图表,我使用了 plotly 的 box 函数,并在分类轴上添加了网格线。

3: 球员的职业生涯分布在哪里?

名单还提供了球员所在俱乐部的信息,即他们不在国家队时所效力的俱乐部。我们汇总了每个俱乐部的球员数量,并仅展示前 30 名。诸如巴萨、切尔西、巴黎圣日耳曼和阿森纳等知名的欧洲和英国俱乐部主导了这个名单。顶尖的亚洲俱乐部包括仁川现代钢铁和武汉江汉大学,这些俱乐部与其本国大量球员有关联。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

世界杯中前 30 名足球俱乐部。数据:维基百科。图片:作者。

这是一个标准的折线图,由于只有一条线,因此图例被关闭。

4: 球员在全球的分布情况如何?

我们按照俱乐部所在国家汇总球员数据。少于 10 名球员的国家被归为“其他”。许多世界杯阵容成员效力于英格兰和美国的俱乐部,这些国家的女子足球代表性强。世界杯冠军西班牙也吸引了许多顶级球员。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

世界杯阵容成员俱乐部。数据:维基百科。图片:作者。

在这里,我创建了一个堆叠条形图,其中分类轴按每个类别的总数排序。颜色方案是定性的 G10 方案,这是 plotly 的默认颜色方案之一。

5: 奖金

最后,让我们来看看参加并赢得世界杯赛事是否值得。我很惊讶地发现,直到 2007 年女子世界杯之前,根本没有奖金发放。在 2023 年澳大利亚/新西兰比赛中,总奖金为 1 亿美元。相比于 2022 年卡塔尔男子世界杯分发的 10 亿美元,这个数字仍然相对较低。如果我们将这两个曲线绘制在对数刻度上,我们可以看到女子奖金的增长速度似乎超过了男子奖金的增长速度。所以未来的某个时候,可能会实现同工同酬。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

女子和男子世界杯的奖金。数据来源:FIFA / 维基百科。图片:作者。

对于这个图表,我创建了两个子图,每个子图包含两条线。y 轴刻度设置为对数刻度。女子早期比赛中零奖金的情况无法在此刻度上显示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正在等待同工同酬的女性。照片由Magnet.me拍摄,来源于Unsplash

反思

我发现 Plotly 使用起来既方便又直观。所有标准统计图都可用。我需要一些时间来习惯图表的自定义,这与我在 matplotlib 中习惯的有所不同。互动功能非常适合数据探索,鼓励读者下载完整的笔记本并尝试使用。对于博客文章,我发现嵌入互动图表有些挑战,因此我选择了静态图表。

参考资料

解析数据中最不寻常的片段

原文:towardsdatascience.com/figuring-out-the-most-unusual-segments-in-data-af5fbeacb2b2?source=collection_archive---------8-----------------------#2023-07-13

如何利用常识和机器学习找到关注的片段

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Mariya Mansurova

·

关注 发表在 Towards Data Science · 13 分钟阅读 · 2023 年 7 月 13 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Klara Kulikova 提供,来源于 Unsplash

分析师经常需要找到“有趣”的片段——那些可以集中精力以获得最大潜在影响的片段。例如,确定哪些客户群体对客户流失的影响最大可能是有趣的。或者你也可以尝试了解哪些订单类型会影响客户支持工作量和公司的收入。

当然,我们可以查看图表来找到这些突出的特征。但这可能是耗时的,因为我们通常跟踪几十个甚至几百个客户的特征。此外,我们需要查看不同因素的组合,这可能会导致组合爆炸。对于这样的任务,使用框架将非常有帮助,因为它可以节省你几个小时的分析时间。

在本文中,我想与大家分享两种找出最突出数据切片的方法:

  • 基于常识和基础数学,

  • 基于机器学习——我们在 Wise 的数据科学团队开源了一个库Wise Pizza,它能用三行代码给你答案。

示例:银行客户的流失

你可以在GitHub上找到这个示例的完整代码。

我们将以银行客户流失数据为例。这个数据集可以在 Kaggle 上找到,许可证为CC0: 公众领域

我们将尝试使用不同的方法找到对流失影响最大的细分群体:图表、常识和机器学习。但让我们从数据预处理开始。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据集列出了客户及其特征:信用评分、居住国家、年龄和性别、客户账户余额等。此外,我们还知道每个客户是否流失——参数exited

我们的主要目标是找出对流失客户数量影响最大的客户细分群体。在此之后,我们可以尝试了解这些用户群体特有的问题。如果我们专注于解决这些细分群体的问题,我们将对流失客户数量产生最大的影响。

为了简化计算和解释,我们将把细分群体定义为一组过滤条件,例如,gender = Malegender = Male, country = United Kingdom

我们将处理离散特征,因此我们需要将连续指标(如agebalance)进行转换。为此,我们可以查看分布并定义合适的桶。例如,让我们看看年龄。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图表由作者提供

分桶连续特征的代码示例

 def get_age_group(a):
    if a < 25:
        return '18 - 25'
    if a < 35:
        return '25 - 34'
    if a < 45:
        return '35 - 44'
    if a < 55:
        return '45 - 54'
    if a < 65:
        return '55 - 64'
    return '65+'

raw_df['age_group'] = raw_df.age.map(get_age_group)

找到数据中有趣的细分群体的最直接方法是查看可视化。我们可以通过柱状图或热图查看按一个或两个维度分割的流失率。

让我们看看年龄与流失之间的关系。35 岁以下的客户流失率较低——不到 10%。而 45 到 64 岁的客户则保留率最差——几乎一半的客户已经流失。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图表由作者提供

我们可以再添加一个参数(gender)以尝试发现更复杂的关系。条形图无法显示二维关系,因此我们可以切换到热图。

女性的流失率在所有年龄组中都较高,因此性别是一个重要因素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者的图表

这样的可视化可以非常有洞察力,但这种方法有几个问题:

  • 我们没有考虑到细分市场的规模,

  • 查看所有可能的特征组合可能会非常耗时,

  • 在一个图表中可视化超过两个维度是有挑战性的。

所以,让我们转向更结构化的方法,这将帮助我们得到一个优先级排序的有趣细分市场列表,并估算其效果。

常识性方法

假设

我们如何计算修复特定细分市场问题的潜在影响?我们可以将其与流失率较低的“理想”情景进行比较。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你可能会想我们如何估算流失率的基准。有几种方法可以做到这一点:

  • 来自市场的基准: 你可以尝试寻找你所在领域中产品的典型流失率水平,

  • 你产品中的高表现细分市场: 通常,你会有一些表现稍好的细分市场(例如,你可以按国家或平台进行划分),你可以将它们作为基准,

  • 平均值: 最保守的方法是查看全球平均值,并估算达到所有细分市场的平均流失率的潜在效果。

我们还是安全起见,使用我们数据集中流失率的平均值作为基准——20.37%。

列出所有可能的细分市场

下一步是构建所有可能的细分市场。我们的数据集有十个维度,每个维度有 3–6 个独特值。总的组合数大约是 120 万。即使我们只有少数几个维度和不同的值,这看起来计算成本也很高。在实际任务中,你通常会有几十个特征和独特值。

我们确实需要考虑一些性能优化。否则,我们可能需要花费数小时等待结果。以下是减少计算的几个小贴士:

  • 首先,我们不需要构建所有可能的组合。将深度限制在 4–6 层是合理的。你的产品团队需要关注由 42 个不同过滤器定义的用户细分市场的可能性非常低。

  • 其次,我们可以定义我们感兴趣的效果规模。假设我们希望将保留率提高至少 1 个百分点。这意味着我们对少于 1%用户的细分市场不感兴趣。如果细分市场的规模低于这个阈值,我们可以停止进一步划分——这将减少操作次数。

  • 最后但同样重要的是,你可以在实际数据集中显著减少数据大小和计算资源的消耗。为此,你可以将每个维度的小特征分组到一个other组。例如,有数百个国家,每个国家用户的比例通常遵循齐夫定律,像许多其他真实数据关系一样。因此,你会有很多国家的用户占比低于 1%。正如我们之前讨论的,我们对这些小用户群体不感兴趣,可以将它们全部分组到一个country = other片段中,以简化计算。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者绘制的图表

我们将使用递归来构建所有筛选器的组合,直到max_depth。我喜欢这个计算机科学的概念,因为在许多情况下,它可以优雅地解决复杂问题。不幸的是,数据分析师很少需要编写递归代码——我可以回忆起在 10 年的数据分析经验中遇到的三个任务。

递归的概念非常简单——就是在执行过程中你的函数调用自身。当你处理层级结构或图形时,它非常有用。如果你想了解更多关于 Python 中递归的内容,可以阅读这篇文章

在我们的案例中,高层概念如下:

  • 我们从整个数据集和没有筛选器开始。

  • 然后我们尝试添加一个额外的筛选器(如果片段大小足够大且我们还没有达到最大深度),并将我们的函数应用于此。

  • 重复前一步骤,直到条件有效。

 num_metric = 'exited'
denom_metric = 'total'
max_depth = 4

def convert_filters_to_str(f):
    lst = []
    for k in sorted(f.keys()):
        lst.append(str(k) + ' = ' + str(f[k]))

    if len(lst) != 0:
        return ', '.join(lst)
    return ''

def raw_deep_dive_segments(tmp_df, filters):
    # return segment
    yield {
        'filters': filters,
        'numerator': tmp_df[num_metric].sum(),
        'denominator': tmp_df[denom_metric].sum()
    }

    # if we haven't reached max_depth then we can dive deeper
    if len(filters) < max_depth:
        for dim in dimensions:
            # check if this dimensions has already been used
            if dim in filters:
                continue

            # deduplication of possible combinations
            if (filters != {}) and (dim < max(filters.keys())):
                continue

            for val in tmp_df[dim].unique():
                next_tmp_df = tmp_df[tmp_df[dim] == val]

                # checking if segment size is big enough
                if next_tmp_df[denom_metric].sum() < min_segment_size:
                    continue

                next_filters = filters.copy()
                next_filters[dim] = val

                # executing function for subsequent segment
                for rec in raw_deep_dive_segments(next_tmp_df, next_filters):
                    yield rec

# aggregating all segments for dataframe
segments_df = pd.DataFrame(list(raw_deep_dive_segments(df, {})))

结果是,我们得到了大约 10K 个片段。现在我们可以计算每个片段的预计效果,筛选出具有负面效果的片段,并查看潜在影响最大的用户群体。

baseline_churn = 0.2037
segments_df['churn_share'] = segments_df.churn/segments_df.total
segments_df['churn_est_reduction'] = (segments_df.churn_share - baseline_churn)\
    *segments_df.total
segments_df['churn_est_reduction'] = segments_df['churn_est_reduction']\
  .map(lambda x: int(round(x)))

filt_segments_df = segments_df[segments_df.churn_est_reduction > 0]\
    .sort_values('churn_est_reduction', ascending = False).set_index('segment')

这应该是一个能提供所有答案的圣杯。但等等,那里有太多重复的片段和相互接续的片段。我们能否减少重复,只保留最有信息量的用户群体?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

梳理

让我们看几个例子。

子片段age_group = 45–54, gender = Male的流失率低于age_group = 45–54。添加gender = Male筛选器并没有使我们更接近具体问题。因此,我们可以排除这些情况。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下面的例子显示了相反的情况:子片段的流失率显著更高,而且更重要的是,子片段包括了来自父节点的 80% 流失客户。在这种情况下,合理的做法是排除credit_score_group = poor, tenure_group = 8+片段,因为主要问题在于is_active_member = 0组中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们筛选掉那些不那么有趣的片段。

import statsmodels.stats.proportion

# getting all parent - child pairs
def get_all_ancestors_recursive(filt):
    if len(filt) > 1:
        for dim in filt:
            cfilt = filt.copy()
            cfilt.pop(dim)
            yield cfilt
            for f in get_all_ancestors_recursive(cfilt):
                yield f

def get_all_ancestors(filt):
    tmp_data = []
    for f in get_all_ancestors_recursive(filt):
        tmp_data.append(convert_filters_to_str(f))
    return list(set(tmp_data))

tmp_data = []

for f in tqdm.tqdm(filt_segments_df['filters']):
    parent_segment = convert_filters_to_str(f)
    for af in get_all_ancestors(f):
        tmp_data.append(
            {
                'parent_segment': af,
                'ancestor_segment': parent_segment
            }
        )

full_ancestors_df = pd.DataFrame(tmp_data)

# filter child nodes where churn rate is lower 

filt_child_segments = []

for parent_segment in tqdm.tqdm(filt_segments_df.index):
    for child_segment in full_ancestors_df[full_ancestors_df.parent_segment == parent_segment].ancestor_segment:
        if child_segment in filt_child_segments:
            continue

        churn_diff_ci = statsmodels.stats.proportion.confint_proportions_2indep(
            filt_segments_df.loc[parent_segment][num_metric],
            filt_segments_df.loc[parent_segment][denom_metric],
            filt_segments_df.loc[child_segment][num_metric],
            filt_segments_df.loc[child_segment][denom_metric]
        )

        if churn_diff_ci[0] > -0.00:
            filt_child_segments.append(
                {
                    'parent_segment': parent_segment,
                    'child_segment': child_segment
                }
            )

filt_child_segments_df = pd.DataFrame(filt_child_segments)
filt_segments_df = filt_segments_df[~filt_segments_df.index.isin(filt_child_segments_df.child_segment.values)]

# filter parent nodes where churn rate is lower 

filt_parent_segments = []

for child_segment in tqdm.tqdm(filt_segments_df.index):
    for parent_segment in full_ancestors_df[full_ancestors_df.ancestor_segment == child_segment].parent_segment:
        if parent_segment not in filt_segments_df.index:
            continue

        churn_diff_ci = statsmodels.stats.proportion.confint_proportions_2indep(
            filt_segments_df.loc[parent_segment][num_metric],
            filt_segments_df.loc[parent_segment][denom_metric],
            filt_segments_df.loc[child_segment][num_metric],
            filt_segments_df.loc[child_segment][denom_metric]
        )
        child_coverage = filt_segments_df.loc[child_segment][num_metric]/filt_segments_df.loc[parent_segment][num_metric]

        if (churn_diff_ci[1] < 0.00) and (child_coverage >= 0.8):
            filt_parent_segments.append(
                {
                    'parent_segment': parent_segment,
                    'child_segment': child_segment
                }
            )  

filt_parent_segments_df = pd.DataFrame(filt_parent_segments)
filt_segments_df = filt_segments_df[~filt_segments_df.index.isin(filt_parent_segments_df.parent_segment.values)]

现在我们有大约 4000 个有趣的段。对于这个玩具数据集,我们在处理后看到顶级段几乎没有差异。然而,使用现实数据时,这些努力往往会有所回报。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根本原因

我们可以做的最后一件事是保留我们段的根节点。这些段是根本原因,其他段被包含在其中。如果你想更深入地了解其中一个根本原因,请查看子节点。

为了仅获取根本原因,我们需要消除最终有兴趣的列表中所有具有父节点的段。

root_segments_df = filt_segments_df[~filt_segments_df.index.isin(
    full_ancestors_df[full_ancestors_df.parent_segment.isin(
        filt_segments_df.index)].ancestor_segment
    )
]

所以,就是这样,现在我们有一个需要关注的用户组列表。由于数据中复杂的关系较少,顶级段仅为一维段,因为只有少数特征可以解释全部效果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

讨论我们如何解释结果是至关重要的。我们得到了一个客户段列表及其估算的影响。我们的估算基于这样的假设:我们可以将整个段的流失率降低到基准水平(在我们的示例中是平均值)。因此,我们估算了修复每个用户组问题的影响。

你必须记住,这种方法仅提供了一个关于关注哪些用户组的高层次视图。它并没有考虑是否能够完全解决这些问题。

我们写了很多代码来获得结果。也许还有另一种使用数据科学和机器学习来解决此任务的方法,不需要如此多的努力。

披萨时间

实际上,还有另一种方法。我们在 Wise 的数据科学团队开发了一个库Wise Pizza,可以在一瞬间找到最引人注目的段。它是基于 Apache 2.0 许可证的开源库,因此你也可以用于你的任务。

如果你有兴趣了解更多关于Wise Pizza库的信息,不要错过 Egor 在数据科学节上的演讲。

应用 Wise Pizza

这个库很容易使用。你只需编写几行代码,并指定你想要的维度和段的数量即可。

# pip install wise_pizza - for installation
import wise_pizza

# building a model 
sf = wise_pizza.explain_levels(
    df=df,
    dims=dimensions,
    total_name="exited",
    size_name="total",
    max_depth=4,
    min_segments=15,
    solver="lasso"
)

# making a plot
sf.plot(width=700, height=100, plot_is_static=False)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者绘制的图表

因此,我们还得到了一个最有趣的段及其对我们产品流失的潜在影响的列表。这些段类似于我们使用之前的方法获得的段。然而,影响估算差异很大。为了正确解释Wise Pizza的结果并理解这些差异,我们需要更详细地讨论它的工作原理。

它的工作原理

这个库基于 Lasso 和 LP 求解器。如果我们简化它,这个库的功能类似于 one-hot 编码,为分段(之前计算的相同分段)添加标志,然后使用 Lasso 回归,目标变量是流失率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如你可能从机器学习中记得的,Lasso 回归倾向于有许多零系数,选择少数显著因素。Wise Pizza找到合适的alpha系数用于 Lasso 回归,从而得到指定数量的分段结果。

对于修订 Lasso(L1)和 Ridge(L2)正则化,你可以参考这篇文章

如何解释结果

影响的估算是系数与分段大小的乘积结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如你所见,这与我们之前估算的完全不同。常识方法估算了彻底解决用户组问题的影响,而 Wise Pizza 的影响显示了对其他选择分段的递增效果。

这种方法的优势在于你可以汇总不同的效果。然而,你在解释结果时需要准确,因为每个分段的影响依赖于其他选择的分段,因为它们可能是相关的。例如,在我们的案例中,我们有三个相关的分段:

  • age_group = 45-54

  • num_of_products = 1, age_group = 44–54

  • is_active_member = 1, age_group = 44–54

对于age_group = 45–54的影响考虑了整个年龄组的潜在效果,而其他估算方法则从特定子组中估算附加影响。这些依赖关系可能会导致结果差异,因为min_segments参数会影响最终分段及其之间的相关性。

关注整体情况并正确解释Wise Pizza结果至关重要。否则,你可能会得出错误的结论。

我认为这个库是从数据中快速获得见解和首批分段候选项的宝贵工具。然而,如果我需要进行机会规模评估和更稳健的分析,以便与我的产品团队分享我们关注的潜在影响,我仍会使用常识方法和合理的基准,因为这样更容易解释。

TL;DR

  1. 在数据中找到有趣的切片是分析师的常见任务(尤其是在发现阶段)。幸运的是,你不需要制作大量图表来解决这些问题。有一些更全面且易于使用的框架。

  2. 你可以使用Wise Pizza ML 库来快速洞察对平均值影响最大的细分领域(它还允许你查看两个数据集之间的差异)。我通常使用它来获取第一个有意义的维度和细分领域列表。

  3. ML 方法可以在一瞬间为你提供高层次的视图和优先级。然而,我建议你注意结果的解释,并确保你和你的利益相关者完全理解它。然而,如果你需要对修复整个用户组问题对 KPI 的潜在影响进行全面估算,使用基于算术的传统常识方法是值得的。

非常感谢你阅读这篇文章。我希望它对你有启发。如果你有任何后续问题或评论,请不要犹豫在评论区留言。

填空自监督在自然语言处理中的应用

原文:towardsdatascience.com/fill-in-the-blanks-self-supervision-in-nlp-f0afb16dc7fd

为什么它强大以及如何解决

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Arun Jagota

·发布于 Towards Data Science ·阅读时间 14 分钟·2023 年 5 月 10 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源 Patrick TomassoUnsplash

预测下一个词在语言建模中有着悠久而成功的历史,尤其是在大型语言模型中。它利用了大量的文本语料库:维基百科、分布在全球的公共网页等。相比其他类型的无监督学习,这种方法在这些语料库上的效果更强,因为学习是有监督的。此外,由于它是自监督的,因此不需要人工创建标记数据。

考虑

曝露在阳光下会导致 __

从一个足够丰富的英语句子语料库中,机器学习应该能够学习一个语言模型,能够合理地填补这些空白,在这个例子中是“皮肤癌”。

我们为什么称之为监督?因为我们从一个完整的标记序列开始,模糊掉最后一个词,要求模型预测它是什么,如果模型预测正确则奖励它,预测错误则惩罚它。所以这就是有监督学习。

最近,这种自监督方法以一种简单而强大的方式得到了扩展。具体而言,要填补的空白可以出现在文本的任何位置。因此,我们可能称之为文本重构任务,而不仅仅是文本补全任务。

以下是一些例子。每个实例是一个词的序列(以粗体标识),后面跟着一个或多个这些词被掩蔽的序列。模型的目标是正确填充这些空白。

**exposure to sunlight causes skin cancer.**
exposure to sunlight causes ___________.
____________________ causes skin cancer.
________ to ________ causes skin cancer.
exposure to sunlight ______ skin cancer.

在这篇文章的副标题中,我们提到这种扩展大大提升了预测下一个词的能力。这里我们解释一下为什么我们这么说。

当然,预测下一个单词可以迫使模型从各种场景中学习,因为很容易组装一个包含数十亿个真实单词序列的数据集。也就是说,将其推广到预测序列中任何掩蔽单词的子集可以大大扩展学习场景的范围。这就是为什么这种掩蔽在 BERT [2] 中扮演了核心角色。

考虑一个包含 n 个单词的序列。如果我们只允许最后一个单词被掩蔽,我们只会从中生成一个标记实例——填入最后一个单词。如果我们允许任何后缀被掩蔽,我们可以从中生成最多 n 个标记实例——填入一个后缀。如果我们允许任何子集的单词被掩蔽,我们可以从中生成约 2^n 个标记实例。这是因为有这么多可以被掩蔽的子集。

此外,正如我们在上面的例子中所见,掩蔽不同的单词将迫使模型学习剩余单词的表示,从而在可能的情况下预测被掩蔽的单词。在我们的例子中,填补右尾的空白迫使模型理解暴露在阳光下的影响,而掩蔽左尾的两个单词则迫使模型学习导致皮肤癌的原因。

这是另一个例子,我们在[3]中覆盖过。

想象一下我们有一个汽车名称的列表。例如:

本田思域、丰田Celica、福特Mustang、吉普Wrangler……

预测下一个单词无疑有助于模型学习特定品牌的模型。例如,CherokeeWrangler(以及其他)是Jeep的模型。然而,通过掩蔽任何单词的额外自我监督也有助于模型学习到模型名称往往能强烈预测品牌。例如,CelicaToyotaMustangFordWranglerJeep,等等。

这种学习将更好地服务于下游应用场景。例如回答问题。

Celica 的品牌是什么?

在本文的其余部分,我们将介绍几种不同的建模方法,并讨论它们的优点和局限性。

我们将讨论的方法在处理这种任务的细微版本时,远不如最先进的大型语言模型。例如,整个段落被掩蔽。

尽管如此,它们更容易理解,也许对一些读者更为熟悉,并且可以使用广泛可用的 NLP 工具包尝试,或者在某些情况下从头开始构建。

数据

假设我们有一组文本文档。文档是一个令牌(单词、标点符号等)的序列。在这篇文章中,我们将假设我们定义的学习任务不会跨越文档边界。

大部分情况下,我们将关注由单个英文句子组成的文档。我们可以想象,这些句子语料库是通过使用 NLP 将较长文档分割成句子从较长的文档语料库中得出的。也就是说,我们讨论的方法同样适用于更长的多句文档。只是对单句文档的描述更为方便。

在这篇文章中,我们将描述一种概念上简单易懂、实现简单且在训练和推断过程中速度较快的方法。

也就是说,它的范围仅限于填补单个遮罩区域的空白,无论是在左尾、右尾还是中间。大型语言模型可以填补多个遮罩区域的空白。此外,LLM 通常会更准确,尤其是在长序列上,如完整段落或甚至整页文本。

方法

我们的方法将包括两个 tries,一个前向 trie 和一个后向 trie,以特定的方式融合在一起。我们将这种数据结构称为前向-后向 trie(FB-Trie)。

我们将使用以下示例来说明前向-后向 trie 数据结构。假设我们的训练集中只有两个句子来构建 trie。

work causes stress.
work is good for you.

首先,让我们看看普通的前向 Trie。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1(作者提供):我们的数据上的前向 Trie

这个 Trie 只捕捉了两个根到叶子的路径上显示的两个单词序列。

Trie 中的一个节点隐式地表示在根到节点路径中以该节点结尾的单词序列。

让我们填补图 1 中未显示的重要细节。一个节点存储训练集中前缀与其匹配的序列数量。因此,在我们的示例中,根节点将存储 2,因为我们的训练集中有两个序列。假设有一个更丰富的训练集,表示 [work, causes] 的节点将存储 15,如果有这么多的序列以 work causes 开头的话。

i 表示一个节点,n(i) 表示它的计数。令 j 表示 i 的一个子节点。从 ij 的弧的概率是 n(j)/n(i),我们将其称为 P(i, j)。

从这个 Trie 中,如果存在明显的高概率扩展,我们可以在右尾填补单个空白。让我们通过示例来说明这一点。

考虑 work ____。我们不会填补这些空白,因为我们可以想象有很多不同的句子以 work 开头。另一方面,如果我们有 work causes ___*,用 stress 填补空白将更为合理

填补左尾的空白

如果填空查询是 ___ causes stress 呢?为了扩展我们的模型以回答这种查询,我们将添加一个后向 Trie。

后向 Trie 是如果我们反转训练集中序列而得到的 trie。它的结构与前向 trie 相同(图 1)。它还包括节点上的计数。

左尾空白现在可以通过相同的推理过程进行填充(如果可能的话),只不过我们查找的是空白需要填充的序列的反向字典树。

在填空输入中,我们将知道空白是位于左尾还是右尾,因此我们将知道是查看输入的前向字典树还是输入反向的后向字典树。

填充中间的空白

考虑当待填充的空白不在任何尾部时。例如工作 __ 压力

对于这个任务,我们将设计一个新的数据结构,这是前向和后向字典树的特殊融合,向两个字典树添加了父节点弧线,并添加了桥接边以从一个字典树跳到另一个。

让我们从向前向字典树添加父节点弧线开始。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2(作者提供):带有父节点弧线的我们的数据上的前向字典树

我们能够添加父节点弧线,因为根据定义,字典树中的每个非根节点都有唯一的父节点。

接下来,我们将向后向字典树添加父节点弧线。

融合前向字典树和后向字典树

接下来,我们将融合这两个字典树。我们下面展示了我们示例中的融合字典树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3(作者提供):我们示例中的前向-后向字典树

前向字典树的节点和弧线用实线表示,而后向字典树的节点和弧线用虚线表示。前向字典树中的父节点弧线用虚线曲线表示。为了减少混乱,后向字典树中不显示父节点弧线,但它们确实存在。

两个字典树通过桥接边融合在一起。这些是没有箭头的虚线边。每条边可以实现为两个节点之间的一对弧线,覆盖两个方向(这未被描绘)。

在图 3 中,只展示了许多桥接边中的几个——实际上是两个。

现在让我们解释这些桥接边是如何添加的。一旦理解了这一点,读者可以想象其余桥接边的位置。

想象一下在一个新序列上进行训练。为了具体说明,假设这是工作导致压力的标记化版本。首先,我们将这个序列插入前向字典树和后向字典树。现在我们考虑这个序列的所有可能的(前缀后缀)分割。接下来,我们反转后缀。

以下是我们将获得的(前缀后缀反向后缀)三元组,排除前缀或后缀为空的情况

**prefix            suffix              reverse suffix**
[work]            [causes, stress]    [stress, causes]
[work, causes]    [stress]            [stress]

现在我们按照如下方法处理每个三元组(前缀后缀反向后缀)。我们在前向字典树中查找前缀以找到它结束的节点。同样地,我们在后向字典树中查找反向后缀以找到它结束的节点。我们现在通过一条桥接边连接这两个节点。

模型大小和训练时间

在描述推理之前,让我们花些时间反思模型的大小以及训练所需的时间。

首先,由于我们有两个字典树——一个前向字典树和一个反向字典树。此外,我们还有桥接边。

在这篇文章中,我们认为模型的大小本身不是问题。最先进的技术可以轻松容纳巨大的模型。

更有趣的问题是训练模型需要多长时间。

首先,训练可以是增量的。也就是说,可以随时向 FB-Trie 添加新序列。事实证明,训练实际上非常快速。这是因为(i)将新序列插入前向字典树及其逆序到反向字典树是很快的,和(ii)枚举所有这些序列的分裂,进行查找以发现要桥接的节点,并添加各种桥接边也是很快的。

使用前向-反向字典树填充空白的说明

让我们用work __ stress来说明这一点。首先,我们查找前向字典树中的节点,称之为u,这是[work]结束的地方。接着我们查找反向字典树中的节点,称之为v,这是[stress]结束的地方。然后,我们沿着从反向字典树到前向字典树的桥接边走。接着,我们沿着[ work, causes ]在前向弧中的父节点走,最终到达[work]。现在我们在两个方向上都到达了相同的节点。在这个过程中我们沿着父弧走的标签序列,经过反转之后,将成为空白的值。在我们的示例中,我们只走了一条反向弧,这条弧标记为causes。所以我们的答案是*“causes”*。

推断:更一般的描述

在我们的work __ stress示例中,空白有一个唯一的解决方案。在一般情况下,L __ R,可能会有多个解决方案*。

(我们略微调整了术语,因为在本节中会有所帮助。L 和 R 是标记序列,而不是字符串。)

下面我们讨论如何处理一般情况。

首先,我们在前向字典树中查找 L 的最大前缀,称之为 L’。接着,我们在反向字典树中查找 R 的最大后缀,称之为 R’。让u表示前向字典树中 L’结束的节点,v表示反向字典树中 R’的逆序结束的节点。

这种情况如下图所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4(作者提供):一般推断——多解情况

由于 v 在反向字典树中不是叶子节点——否则就没有空白可以填充——因此必须至少有一条桥接边接触到v,如图 4 中的标注所示。

考虑任何一条这样的桥接边,并让w表示在前向字典树另一端的节点。我们按照前向字典树中的父弧顺序跟踪,从w开始。当我们首次到达一个节点,称之为x,这个节点位于前向字典树中的路径 L’上时,我们停止。这种情况总是会发生(见下一段)。

最佳情况是x等于v。最坏情况是x是前向字典树的根。

逆转从 wx 的路径上的标签顺序会产生一种推断的解决方案。更准确地说,这个解决方案是针对填空问题 L’’ __ R’,这可能比我们开始时的问题 L __ R 更宽泛。

进一步扩展解决方案

每条触及 v 的桥接边都会生成一个唯一的解决方案。因此,形式为 L’’ __ R’ 的解决方案的数量就是触及 v 的桥接边的数量。请注意 L” 取决于 w

我们可以通过从 u 开始而不是 v 来反向推断,从 uw 走一条桥接边。这次 w 是反向字典树中的一个节点。然后我们在反向字典树中从 w 顺序地沿父节点弧走,直到第一次遇到反向字典树中的 R’ 节点,我们将其称为 x。 (这次 x 是反向字典树中的一个节点,而不是正向字典树中的。) 我们得到另一组形式为 L’ __ R’’ 的解决方案。注意 R’’ 取决于 w

两组解决方案可能会重叠。这些集合容易去重,因为解决方案是由表示填充部分的路径的端点唯一确定的。请注意,路径本身可能不同,但端点(忽略起点和终点)将是相同的。

让我们通过图 3 中的“work __ stress”的例子来说明这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5(作者提供):两种方法来填入“causes”在“work __ stress”中。

如果我们按照所描述的算法进行,有两种方法可以将“causes”填入“work __ stress”中。一种方法是从反向字典树中的[stress]的桥接边开始,另一种方法是从正向字典树中的[work]的桥接边开始。尽管这两种解决方案是通过不同的路径找到的,但在忽略起始点和终点后,两条路径上的端点是相同的:正向字典树中的[work]和反向字典树中的[stress]。

如果我们仅允许从其中一个字典树开始,我们不会得到重复。但我们不能排除可能会遗漏某些解决方案的可能性。

这是一个例子。假设我们在以下两个字符串的分词版本上进行了训练。

work causes burnout.
work causes stress.

考虑提示“work __ stress”。从反向字典树中触及[stress]的桥接边开始,我们会得到解决方案“work causes stress”。从正向字典树中触及[work]的桥接边开始,我们会得到解决方案“work causes burnout”。

很合理地怀疑第二个答案是否应该被认为是一个有效的解决方案,因为它忽略了词语stress。这是一个需要建模者做出的决定。这两种观点都有其合理性。

在这篇文章中,我们的观点是,如果有人想将第二个答案视为有效的解决方案,这可以通过枚举两个方向上的所有解决方案然后去重来实现。

评分解决方案

当填空题有多个解决方案时,为了能够按优劣顺序呈现它们,对它们进行评分是合理的。

我们已经看到一个评分有意义的例子。对于提示“工作 __ 压力”,如果我们认为“工作 导致倦怠” 也是一个解决方案,那么它应该比“工作* 导致 *压力”的评分低。这是因为前者忽略了提示中的单词压力,而后者则没有

在这个例子中,前一个解决方案的粗体字比后一个多这一事实在此没有作用。答案中的单词数量本身并不重要,重要的是被忽略的提示信息的量。

现在考虑这个提示:“工作 __”。假设训练集仅包含这两个字符串

work causes burnout.
work causes stress.

工作 导致倦怠” 和 “工作 ***导致压力”***都是不错的解决方案。

现在想象一下,训练集中实际上包含了这两个字符串的多个副本,并且字符串“工作导致压力”的出现频率远高于工作导致倦怠。这就意味着,将“工作 ***导致压力”*评为比“工作 __”更好的解决方案是合理的,而不是“工作 导致倦怠”

对于上一段的场景,提供所需排名顺序的评分很容易实现。从前向查找树上的节点[工作, 导致]开始,选择标记为“压力”的弧的概率高于选择标记为*“倦怠”*的弧的概率。这些概率可以从之前讨论的前向查找树中存储的信息中轻松计算出来。

对于填空在左尾的提示,我们可以类似地对解决方案进行排名。这次我们使用的是反向查找树,而不是前向查找树。

唯一剩下的情况是当空白在中间,并且两个解决方案使用相同的提示信息时。也就是说,两个解决方案的形式为 L M1 R 和 L M2 R,其中 L 和 R 在两个解决方案中是相同的,但 M1 和 M2 不同。

为了覆盖这种情况,我们将定义解决方案 L M R 的评分如下。写作 M = [m1] M’ [m2],其中m1 和m2 是 M 中的第一个和最后一个标记。M’可能为空,这种情况下m1 等于m2。

我们将定义 L M R 的评分为前向查找树中 P(m1|L)与反向查找树中 P(m2|R)的乘积。

总结

在这篇文章中,我们首先讨论了填空自监督问题作为训练大型语言模型的一种强大方法。然后,我们提出了使用自定义融合的前向和反向查找树来解决这个问题的方法。

尽管这种解决方案在与现代深度学习和基于变换器的大型语言模型相比时并不具备竞争力,但在较小版本的问题中,特别是在回答单句填空题时,它可能非常有效。

从零实现相对容易理解且快速训练,同时也支持增量训练。

参考文献

  1. towardsdatascience.com/contextual-text-correction-using-nlp-81a1363c5fc3

  2. arxiv.org/pdf/1810.04805.pdf [BERT]

  3. medium.com/towards-data-science/multi-task-learning-4531eb32d77b

最终的 DXA-国家

原文:towardsdatascience.com/final-dxa-nation-f0309d718980

基于长期图像的 AI 模型在健康和医学领域

AI 可以看到终点!深度学习通过单次和顺序体成分成像预测全因死亡率

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Lambert T Leong, PhD

·发表于 Towards Data Science ·阅读时间 9 分钟·2023 年 7 月 22 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DXA 成像提供了多种体成分可视化类型。(图片由作者提供)

关键点,TLDR:

  • 结合体成分成像和元数据(例如年龄、性别、握力、步速等)可以提供最佳的 10 年死亡率预测

  • 相比单次记录模型,长期或顺序模型整体表现更佳,突显了在健康数据中建模变化和时间依赖性的必要性。

  • 长期模型有潜力提供更全面的健康评估

  • 阅读论文

人工智能(AI)和机器学习(ML)正在革新医疗保健,推动我们迈向精准医疗时代。开发 AI 健康模型的动机是减少死亡和疾病,并延长高质量的生活。经过良好训练的模型具有更全面分析数据的能力,提供了更全面的健康评估。

单次记录与长期模型

基于图像的医学 AI/ML 模型现在已经达到了一个成熟的阶段,它们常常能与人类表现相媲美甚至超越人类,熟练地识别那些容易被人眼忽视的模式和异常。然而,大多数这些模型仍然在单一时间点的数据上运行,仅提供一个特定时刻的健康快照。无论是单模态还是多模态模型,它们往往处理的是在相对相似时间框架内收集的数据,这些数据构成了预测的基础。然而,在医学应用的 AI/ML 的更广泛背景下,这些单一时间点的模型只是第一步——所谓的“低悬果实”。医学 AI 研究的一个前沿是纵向模型,它们提供了对一个人健康状况随时间变化的更全面的视角。

纵向模型旨在整合多个时间点的数据,捕捉个体健康轨迹而非单独的瞬间。这些模型利用人类健康的动态特性,因为生理变化是不断发生的。将这些变化映射到特定的结果或健康问题上,可能会成为预测医疗的游戏规则改变者。纵向数据的概念在临床实践中并不陌生——它经常被用来监测衰老和预测脆弱性。一个典型的例子是骨矿密度(BMD)的跟踪,这是骨质疏松症和脆弱性的关键标志。定期评估 BMD 可以检测到显著的减少,预示潜在的健康风险。

纵向模型开发挑战

从历史上看,纵向模型的开发面临了几个重要挑战。除了每个个体需要处理的大量数据和计算外,最关键的障碍在于纵向医学数据的策划。与单一时间点的数据不同,纵向数据涉及在较长时间内跟踪患者的健康信息,通常跨越多个医疗机构。这需要细致的数据组织和管理,使得策划过程既耗时又昂贵。多个成功的研究已经获得资助以前瞻性地收集纵向数据。这些研究报告了与患者在较长观察期内的保留相关的挑战。因此,尽管纵向模型具有潜在的好处,但其开发仍然是一个复杂且资源密集的任务。

目标

体成分的变化,包括瘦体组织、脂肪软组织和骨骼的比例,已知与死亡率相关。在我们的研究中,我们旨在利用体成分信息来更好地预测全因死亡率,简单来说,就是预测一个人可能的生命时间线。我们评估了基于单一时间点和纵向数据构建的模型的性能,分别称为我们的“单记录”和“顺序”模型。单记录模型使我们能够评估哪种信息最能预测死亡率。开发顺序模型的目的是捕捉随时间变化的情况,并评估这些变化如何影响死亡率预测。

数据

本研究的数据来自一个纵向研究,即健康、老龄化与体成分(Health ABC)研究,在该研究中,跟踪和监测了 3000 多名年长的多种族男女成人,持续时间长达 16 年。这项研究产生了一个丰富而全面的纵向数据集。作为研究的一部分,患者接受了全身双能量 X 射线吸收测量(TBDXA)成像,并收集了几项元数据。为了遵循最佳建模实践并避免数据泄漏或减轻过拟合,数据被分为训练集、验证集和保留测试集,按照 70%/10%/20%的比例划分。

我们使用全身双能量 X 射线吸收测量(TBDXA)成像来量化体成分,这一直被认为是金标准成像模式。历史上,患者元数据,包括年龄、体重指数(BMI)、握力、步速等变量,被用于评估衰老/死亡率,并作为体成分的替代测量。由于 DXA 扫描仪的可及性有限,患者元数据和体成分的替代测量得到了广泛使用。最近,随着扫描成本的降低以及不再需要医生转诊/订单/处方,可及性得到了极大改善。

单图像模型

构建了三个单记录模型,每个模型使用不同的数据输入,但所有模型的输出都是 10 年死亡概率。第一个模型仅使用患者元数据,使用了一个 32 单元的 ReLU 激活隐藏层和一个 Sigmoid 预测层的神经网络。第二个模型仅使用 TBDXA 图像作为输入,它包括一个经过修改的 Densenet121,该模型被修改为处理两个颜色通道而不是大多数自然图像中的三个颜色通道(RGB)。DXA 的双能量特性导致高低 X 射线图像,这些图像完全注册并堆叠成两个图像通道。第三个模型将模型一中的元数据嵌入与模型二中的 TBDXA 图像嵌入结合,然后通过一个 512 单元、一个 64 单元的全连接 ReLU 层进行处理,最后通过一个 Sigmoid 预测层进行预测。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据输入、模型架构和单记录模型方法图(作者提供的图片)

纵向/序列模型

构建并评估了三个连续模型。单记录模型架构作为每个连续模型的基础,但去除了 sigmoid 预测层,使输出成为表示特征嵌入的向量。在研究过程中,收集了每位患者在多个时间点的数据。每个时间点的数据被输入到适当的模型中,以获得相应的特征向量。每位患者的特征向量被排序并堆叠成一个序列。训练了一个长短期记忆(LSTM)模型,以处理特征向量序列并输出 10 年的死亡率预测。如前所述,进行长期研究存在若干困难,其中保留和数据收集是常见问题。我们的研究也遇到这些问题,因此一些患者的数据点比其他患者更多。选择 LSTM 模型作为序列建模方法,因为它们不受限于每位患者使用相同的输入序列长度。即,LSTM 可以处理长度不同的序列,从而消除了如果患者数据点不足(约 10 个),需要填充序列的问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据输入、模型架构和连续模型方法图(作者提供的图片)

图像 + 元数据纵向模型胜出

在保留的测试集上的接收操作特征曲线下面积(AUROC)显示,元数据在单记录和连续模型中均优于仅使用 TBDXA 图像。然而,将元数据和 TBDXA 成像结合在这两种建模范式中都产生了最佳的 AUROC,这表明成像包含了元数据未捕捉的有用信息,能够预测死亡率。另一种解释是,元数据并不是预测死亡率的体成分的完整替代指标。如果它们是完整的替代指标,将 TBDXA 成像与元数据结合不会显著提高或改变 AUROC。组合结果产生了更好的 AUROC,表明成像提供了超出元数据捕捉的信息,进一步证明了成像的有效性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单记录和连续模型 AUC 性能(作者提供的图片)

总体来看,纵向或序列模型的表现优于单一记录模型。这一点在所有建模方法和输入数据类型(元数据、仅图像、组合的元数据和图像)中都适用。这些结果展示了建模变化及健康数据时间依赖性的重要性。

我们进行了综合辨别改进(IDI)分析,以评估将成像与元数据结合使用相较于仅使用元数据的好处。该分析是在表现优于单一记录模型的序列模型上进行的。IDI 的结果为 5.79,其中集成敏感性和特异性分别为 3.46 和 2.33。这表明,将成像与元数据结合使用可以将模型正确识别出未来 10 年内无法生存者的能力提高 3.46%,并将正确识别出未来 10 年内能够生存者的能力提高 2.33%。总体来说,这表明模型性能的改善大约为 5.8%。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

综合辨别改进(IDI)分析结果(作者提供的图像)

那么,怎么了?

我们的研究强调了纵向人工智能/机器学习模型在预测医疗领域,特别是全因死亡率方面的潜力。单一记录模型和纵向模型的比较分析显示,后者表现更佳,这表明建模时间变化在健康数据分析中的关键作用。我们的发现具有临床意义,包括通过考虑患者历史或纵向数据的模型提供更准确和全面的健康评估。此外,我们对可解释性人工智能的深入分析提供了与高 10 年死亡概率密切相关的变量的见解。其中一些变量是可改变的,可以在临床上进行干预,为许多人提供了改善其寿命和健康期的机会。虽然开发纵向健康模型所需的数据存在,但适当的基础设施和机构支持尚未完全到位,以便高效地进行数据整理和大规模开发这些模型。然而,许多人正在努力克服这些障碍,纵向模型的开发是医学中人工智能众多令人兴奋的前沿之一。

这些发现的临床意义深远。纵向模型有可能通过提供关于患者健康轨迹的更精确、个性化的预测来改进护理。这样的模型可以指导主动干预,从而提升护理结果,甚至可能延长生命。此外,使用元数据和影像数据为未来的 AI/ML 模型树立了新的标准,建议采取协同的方法以获得最佳结果。这加强了对多维度、细致数据的需求,以准确全面地描绘患者的健康状况。这些发现代表了 AI/ML 在医疗保健应用中的重要进展,突显了在追求精准医疗过程中的激动人心的前景。

更多资源:

阅读论文

[## 深度学习预测基于纵向全身 DXA 成像的全因死亡率 …

死亡率研究已识别出预测全因死亡风险的生物标志物。这些标记物中的大多数,例如 …

www.nature.com](https://www.nature.com/articles/s43856-022-00166-9?source=post_page-----f0309d718980--------------------------------)

关于 IDI 和已发布示例的更多信息:

## 曲线下面积及其应用

医生和数据科学家们,这里有一个关于 IDI 和 NRI 的介绍及一个 Python 代码示例。AUC 可能并不总是足够的 …

towardsdatascience.com [## 双能量三室乳腺成像用于成分生物标志物以提高检测 …

尽管乳腺成像如全视场数字乳腺摄影和数字乳腺断层扫描有助于减少 …

www.nature.com](https://www.nature.com/articles/s43856-021-00024-0?source=post_page-----f0309d718980--------------------------------) [## GitHub - LambertLeong/AUC_NRI_IDI_python_functions: 自定义 Python 函数帮助你进一步 …

自定义 Python 函数帮助你进一步分析机器学习模型和诊断测试 - GitHub …

github.com](https://github.com/LambertLeong/AUC_NRI_IDI_python_functions?source=post_page-----f0309d718980--------------------------------) [## 曲线下面积与集成歧视改进和净重新分类的结合

医生和数据科学家,这里是关于 IDI 和 NRI 的介绍,并附有一个 Python 编码示例。AUC 可能并不总是足够的…

www.lambertleong.com

为你的下一个数据科学侧项目寻找灵感

原文:towardsdatascience.com/find-inspiration-for-your-next-data-science-side-project-8b05851dce91?source=collection_archive---------7-----------------------#2023-03-09

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 TDS Editors

·

关注 发表在 Towards Data Science · 作为 通讯 发送 · 阅读时间 3 分钟 · 2023 年 3 月 9 日

侧项目可以成为积极学习的完美工具,但我们知道许多数据科学家很难挤出时间来启动一个。即使你有一些空闲时间,确定一个想法也可能是一个挑战:它必须与你的兴趣相关,范围合理,并且足够具有挑战性(但又不是难到让人痛苦的程度)。

好的,我们在这里提供帮助!

本周,我们汇聚了一系列强大的动手教程,可能会激发你的创造力,并鼓励你涉足新的主题。逐步跟随其中一个(或多个),或者将这些推荐作为开始全新学习冒险的起点。不论如何,最重要的是选择某个东西。你将在实践中整理细节。

  • 立即上手数据集成管道。如果你迫不及待想要深入代码,Marie Truong的 ELT(提取、加载、转换)工作流教程将迅速让你“卷起袖子”动手实践。除了其他有用的组件,你还将操作 API 并熟悉 BigQuery。

  • 创建自定义微服务。所有关于 AI 的喧嚣是否让你感到有些迷茫?重新找到方向的好方法是构建一个使用这项快速发展的技术的实际应用。Mason McGough的项目讲解将展示如何构建一个去除图像中人物的 Stable Diffusion 应用——这本身是个很酷的主意,也可能激发你探索其他方向。

  • 无需代码,只需数学。掌握一个复杂的概念时,当其各个元素变得更加具体时会更容易。例如:Aparna Dhinakaran和 Jason Lopatecki 对 Jensen-Shannon Divergence 的介绍,他们耐心地解释了其背后的数学以及在监控模型漂移中的实际应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由Andrew Neel提供,来自Unsplash

  • 构建地理空间工具的全程指南。如果你的学习风格适合详细、稳步的指导,试试Jacky Kaub关于创建基于地图应用程序的系列教程。它将带你从概念验证到最小可行产品,经过三篇耐心的文章;到第一部分结束时,你将已经有一个简约的演示。

  • 谁想从零开始学习深度学习? Piotr Lachert 的首次 TDS 文章以一个简单的前提开始:“检查您是否真正理解神经网络如何学习的最佳方法是全程自己实现这个过程。” Piotr 随后确切地做到了这一点,带领读者通过 Python 实现基本神经网络。

  • 调查因果推断的细节Nazlı Alagöz 的教程以一个假设的音乐流媒体服务为例,阐明了提取因果洞察的复杂性,并详细探讨了在处理受多次治疗时间和多个时间段影响的数据时,差异中的差异(DiD)方法的局限性。

  • 更多因果关系,仅仅因为。如果 Nazlı 的帖子激发了您对因果推断的好奇心,并且您准备深入了解,您很幸运:我们最近的三月版专注于这个重要主题,您将找到几个优秀的教程。

感谢您这周的时间和支持!如果您喜欢我们发布的作品(并希望获取所有内容),请考虑 成为 Medium 会员

直到下一个变量,

TDS 编辑团队

使用量子计算机寻找暗物质

原文:towardsdatascience.com/finding-dark-matter-using-a-quantum-computer-a99f4bff4685

QML — 量子机器学习在高能和粒子物理的有趣应用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Prashant Mudgal

·发布于 Towards Data Science ·阅读时间 9 分钟·2023 年 11 月 3 日

背景

今年的八月,致力于 IBM 全球量子暑期学校,在那里我不仅在压缩的时间表和紧凑的日程中学到了基础知识,还学到了一些量子计算的应用。在经过 4 周艰苦的学习后获得的 徽章 本身就是一段 “量子体验”,因为你以为你了解自己在做什么,但同时你对发生了什么一无所知。这个月的课程从量子电路基础转到变分算法的速度很快,几乎没有时间来“做自己的研究”和亲自参与应用部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Dynamic Wang 提供,来源于 Unsplash

就应用而言,量子化学、量子模拟和一些非常复杂的建模任务都符合可以用量子计算机解决的问题的标准。话虽如此,还有另一个正在蓬勃发展的领域,受到用户和研究人员的极大关注,那就是量子机器学习——简称 QML。

我认为 QML 应该是传统机器学习的合理继承者,于是我开始了这项工作。现在,我希望能找到一个不会因为数据量庞大、复杂模式难以识别而让机器学习算法无法直接解决的问题,但又是我可以在我那台简陋的机器上编程解决的问题。我没有再去寻找其他领域,我们的老朋友物理学正好适合,它在其怀抱中隐藏着一系列复杂但有趣的问题,而且从事这些问题听起来在智力上也很酷。

就这样。

问题陈述

我决定处理在与大型强子对撞机(CERN)相关的 OPERA 实验(振荡项目与乳胶追踪装置)下研究的暗物质分类问题。

问题陈述

简而言之,我们将训练一个分类器来区分信号和噪声。信号是暗物质的存在,而噪声意味着没有信号或完全是其他东西。

很简单!

直觉

让我们稍微详细讲解一下实验的背景,以便形成一些直觉。

暗物质是一种神秘且尚未被探测到的物质形式,它不会与电磁辐射(如光)发生相互作用。人们认为它占据了宇宙总质量的近 80%。之所以称之为“暗物质”,是因为它无法通过望远镜或其他探测电磁辐射的仪器直接观察到。

为什么寻找暗物质是一个挑战?

这很具挑战性,因为我们不知道自己在寻找什么。

  1. 隐形:暗物质不会与光相互作用,这就是为什么我们真正不知道自己在寻找什么,虽然有许多理论,但仍没有共识。

  2. 背景噪声:设计用于探测暗物质的实验必须应对各种背景噪声,这些噪声可能会模拟暗物质的预期信号。区分实际的暗物质相互作用和这些背景信号是一个重大挑战。暗物质与常规物质的相互作用非常微弱,使得在实验中探测和区分背景噪声变得困难。

  3. 多种可能性:暗物质的理论候选者有很多,这需要不同的探测方法。科学家们正在探索这些可能性,这增加了寻找暗物质的复杂性。

OPERA 实验中到底发生了什么?

OPERA 位于意大利的格兰萨索国家实验室。这是一个中微子物理实验,主要关注中微子振荡的研究。它并不是专门用于寻找暗物质的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图像

当一个假定的暗物质粒子(我们正在寻找的)与铅原子核碰撞时,原子核会以电子束的形式发射电子,这些电子束在屏幕上被探测到。这就是我们要寻找的信号。然而,当一个中微子与铅原子核碰撞时,它也会产生电子,并以相同的方式产生电磁冲击,这会将信号与噪声混淆。我们正试图区分这个信号和噪声。

我们的计划

基本上,我们需要筛选数据并区分信号和噪声,这可以通过传统的机器学习方法完成,但仍然是一个艰巨的任务。在一个拥有 1000 万次碰撞的数据集中,只有大约 1 万次会对应信号。这种数据集中的不平衡和稀疏使问题变得偏斜且困难。因为我们喜欢挑战,我们会加一个小难度,使用量子机器学习算法而非传统算法(对以连词开头的句子表示歉意)。

数据

LHC 网站上有大量数据集在这里可供使用;本实验使用的数据集可以在这里找到。

许可证: 数据集根据CC0 (CC Zero) 发布,这是创意共享公共领域奉献许可证 (opendata.cern.ch/record/16541)

代码可以在我的GitHub 仓库中找到。

数据包括两个 h5 文件,open30.h5 和 test.h5;h5 是层次数据格式,用于以压缩方式存储和组织大量数据。

数据包含以下变量:

  1. X — 基础轨道的 X 坐标

  2. Y — 基础轨道的 Y 坐标

  3. Z — 基础轨道的 Z 坐标

  4. TX — 从原点投影到 X 轴的角度

  5. TY — 从原点投影到 Y 轴的角度

  6. 信号 — 一个二元变量,1 表示信号,0 表示噪声

IBM 的量子库 — qiskit 0.44.3

import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

关于变分量子算法的说明

量子算法设计用于在量子计算机上运行,但目前我们处于 NISQ — 噪声中等规模量子计算机时代,这使得结果的重现变得困难。当前的量子计算机非常容易受到噪声的影响,甚至微小的热力学条件变化或其他电路问题都会对结果产生很大影响。我们想应用的逻辑门因为噪声会变成其他东西。这是不可取的。

聪明的研究人员开发了所谓的变分算法,它们利用经典计算机和量子计算机来提高速度和准确性。

实质上,所有算法都使用某种形式的优化和参数调整,变分算法所做的是利用量子计算机来近似成本函数,然后在经典计算机上计算成本函数的新参数值,再用新值在量子计算机上运行。这样,计算就分布在经典计算机和量子计算机之间,加速了过程。

我们将在这里使用变分量子分类器,因为任务是分类信号和噪声。有关 IBM VQC 的更多信息,请访问:learn.qiskit.org/course/machine-learning/variational-classification

建模

我们先来看看数据和变量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源于作者

让我们查看配对图,以了解变量之间是否存在相关性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源于作者

好吧,存在一个模式,但相当复杂!

在完成常规的样板工作,包括采样、缩放和训练测试拆分后,我们已经准备好进行量子模型训练。

在继续之前,让我们运行支持向量分类算法,这样我们就有了传统机器学习的基准。

from sklearn.svm import SVC

svc = SVC()
model_classical = svc.fit(train_features, train_labels) 

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源于作者

在测试数据上 70%的准确率并不算太好,但我这里没有进行太多的特征工程。一旦我进行特征工程,它会有所改善。

现在,轮到量子计算机了。

问题被以门和电路的形式进行表述,这些门和电路将量子比特(量子位)输入到量子计算机中。

我们没有丢弃任何特征——TX、TY、X、Y、Z;我们会使用所有这些特征,因此我们电路中使用的量子比特数量将是 5。

 num_features = features.shape[1] #5

feature_map = ZZFeatureMap(feature_dimension=num_features, reps=1)
feature_map.decompose().draw(output="mpl", fold=20)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源于作者

电路的样子就是这样。它输入 5 个量子比特,应用了 Hadamard 和 P 门。Hadamard 门将量子比特的基态从|0>变为|+>,从|1>变为| — >,而 P 门则使得单量子比特绕 Z 轴旋转。

形成电路后的下一步是 Ansatz,这是量子世界中相当常见的术语;它在德语中意为“方法”,但在物理学和数学中指的是一种经过教育的猜测。

所以,我们需要做的就是对参数进行经过教育的猜测——这将创建一个量子态,并在量子计算机上执行。执行值将与期望值进行比较,根据偏差程度,优化器将调整参数或 ansatz,直到我们达到一个足够好或满意的值。

from qiskit.circuit.library import RealAmplitudes

ansatz = RealAmplitudes(num_qubits=num_features, reps=3)
ansatz.decompose().draw(output="mpl", fold=20)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源于作者

你会看到应用了很多 R 门。本质上,所有量子比特只是绕其轴旋转以获得一些任意的起始值,这就是 ansatz。

现在,让我们在训练数据上拟合 VQC。

optimizer = COBYLA(maxiter=100)

vqc = VQC(
    sampler=sampler,
    feature_map=feature_map,
    ansatz=ansatz,
    optimizer=optimizer,
    callback=callback_graph,
)

vqc.fit(train_features, train_labels)

回调图非常酷。就像实时获取你行为的结果一样。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

好的,下行趋势是有希望的,这意味着它正在学习,但只在测试数据上进行拟合才能告诉我们是否存在过拟合。

train_score_q4 = vqc.score(train_features, train_labels)
test_score_q4 = vqc.score(test_features, test_labels)

print("Quantum VQC on the training dataset:",train_score_q4)
print("Quantum VQC on the test dataset:", test_score_q4)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

相较于传统的机器学习,略微更好。我在本地机器上使用模拟器运行了它。也许在真实的量子计算机上运行时效果会更好(没有什么阻止我们,只是需要排队,并且由于服务器负载的增加,简单的任务如加法需要几个小时才能完成,这并不是因为计算慢,而是因为越来越多的人排队使用计算时间)或者花更多时间进行特征工程。

结束语

话虽如此,我很确定目前传统的机器学习算法会优于量子算法,特别是在分类任务中,因为大量研究和资源已经投入到使其稳健和复杂化的工作中。一旦量子机器学习经历这样的升级,它将成为一场公平的竞争。

这并不意味着量子机器学习会取代机器学习,这远非事实,相反,量子计算是针对那些经典计算机无法在多项式时间内解决或甚至无法近似的问题。机器学习会有它的地位,量子机器学习也会在更大的框架中占有一席之地。

本文并不旨在展示机器学习或量子机器学习的威力,而只是展示两者之间的相似性——它们在执行上有所不同但在本质上类似,两者都依赖于特征工程和超参数的选择。

在结束之前,看看信号中是否存在某种聚类将会很有趣。我们已经将信号与噪声分开,我们能否对其进行聚类,看看是否形成了暗物质粒子的电磁喷发?

kmeans = KMeans(n_clusters=5).fit(train)
clustering_labels = kmeans.labels_
X_train = train.sample(frac=0.05)

clusters['cluster'] = clustering_labels

fig = plt.figure(figsize = (20,20))
ax.scatter(X_train.X, X_train.Y, X_train.Z, c=X_train.cluster)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

不错!它们虽然不具备独特性,但也不糟糕。可以看到一些模式。簇的垂直特性是由于质量和碰撞后的轨迹角度。

有趣!

从嘈杂的数据中,我们提取了可能成为暗物质粒子相互作用候选者的最佳轨迹。

我希望这篇小文章能鼓励你迈出量子跃迁。欢迎通过 Twitter 或邮件联系我;像往常一样,我愿意接受批评和建议,这些能帮助我成长和学习。

PS:再一次,代码在我的 GitHub 仓库中 这里

在非结构化数据中找到数据切片

原文:towardsdatascience.com/finding-data-slices-in-unstructured-data-f36244bb044e?source=collection_archive---------7-----------------------#2023-08-18

简要介绍了数据切片方法,包括对 CIFAR-100 数据集的实际操作示例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Stefan Suwelack

·

关注 发表在 Towards Data Science ·9 min read·2023 年 8 月 18 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

CIFAR100 中的数据切片。来源:作者创作。

tl;dr:

数据切片是数据中具有语义意义的子集,在这些子集中,模型的表现异常。当处理非结构化数据问题(例如图像、文本)时,找到这些切片是每个数据科学家的重要工作。在实践中,这项任务涉及大量的个人经验和手工工作。在本文中,我们介绍了一些使数据切片发现更加系统化和高效的方法和工具。我们讨论了当前的挑战,并展示了一些基于开源工具的实际操作示例工作流。

有一个基于 CIFAR100 数据集的互动演示可用。

介绍

调试、测试和监控人工智能(AI)系统很困难。大多数软件 2.0开发过程中的工作都花在了策划高质量数据集上。

开发强大机器学习(ML)算法的一个重要策略是识别所谓的数据切片。数据切片是语义上有意义的子集,其中模型表现异常。识别和跟踪这些数据片段是每个以数据为中心的 AI 开发过程的核心。它也是在医疗保健和自动驾驶辅助系统等领域部署安全 AI 解决方案的核心方面。

传统上,寻找数据切片一直是数据科学家工作的重要组成部分。在实践中,寻找数据切片很大程度上依赖于数据科学家的个人经验和领域知识。随着以数据为中心的人工智能(AI)运动的发展,许多当前的工作和工具旨在使这一过程更加系统化。

在本文中,我们概述了在非结构化数据上找到数据切片的当前状态。我们特别展示了一些基于开源工具的实际操作示例工作流程。

什么是切片查找?

数据科学家一直在使用简单的手动切片查找技术。最著名的例子可能是混淆矩阵,这是一种用于分类问题的调试方法。在实践中,切片查找过程依赖于预计算的启发式方法、数据科学家的个人经验以及大量的互动数据探索。

一个经典的数据切片可以通过对表格特征或元数据的谓词连接来描述。在一个人员数据集中,这可能是某个年龄范围内的男性,身高超过 1.85 米。在一个发动机状态监测数据集中,一个数据切片可能由某个转速、操作时间和扭矩范围的数据点组成。

在非结构化数据的情况下,语义数据切片定义可能更加隐含:它可以是人类可理解的描述,如“在山区的弯曲道路上,轻微降雨情况下的驾驶场景”。

在非结构化数据集上识别数据切片可以通过两种不同的方式进行:

  1. 可以使用经典信号处理算法(例如黑暗图像、低信噪比音频)或用于自动标记的预训练深度神经网络从非结构化数据中提取元数据。然后可以在这些元数据上进行切片查找。

  2. 嵌入空间中的潜在表示可以用于对数据集群进行分组。这些集群可以被检查以直接识别相关的数据切片。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

识别非结构化数据上的数据切片的工作流程。来源:作者创建。

自动化切片发现技术总是试图在切片的支持度(应该很大)和模型性能异常的严重性(也应该很大)之间取得平衡。

表格数据上的切片发现方法与决策树有很多相似之处:在机器学习模型分析的背景下,这两种技术都可以用来制定描述模型错误存在位置的规则。然而,有一个重要的区别:切片发现问题允许重叠切片。这使得问题在计算上变得困难,因为更难以修剪搜索空间。

为什么数据切片发现很重要?

尤其是在过去十年中,机器学习社区从基准数据集中受益匪浅:从 ImageNet 开始,这些数据集和竞赛成为深度学习算法在非结构化数据问题上的成功因素。在这种背景下,新算法的质量通常基于极少的定量指标,如 F1 分数或平均精度。

随着越来越多的机器学习模型投入生产,现实世界的数据集与其基准数据集的差异变得显而易见:真实数据通常非常嘈杂和不平衡,但也富含元数据。对于某些用例,清理和标注这些数据集可能代价高昂。

许多团队发现,迭代训练数据集并监控生产中的漂移对于构建和维护安全的 AI 系统是必要的。

发现数据切片是这一迭代过程的核心部分。只有了解模型的失败点,才能提升系统性能:通过收集更多数据、纠正错误标签、选择最佳特征或简单地限制系统的操作领域。

为什么数据切片发现如此困难?

切片发现的一个关键方面是其计算复杂性。我们可以通过一个小例子来说明这一点:考虑 n 个二进制特征,采用独热编码(例如,通过分箱或重新编码获得)。那么所有可能特征组合的搜索空间是 O(2^n)。这种指数性质意味着通常使用启发式方法来进行修剪。因此,自动化切片发现不仅需要很长时间(取决于特征数量),而且输出不会是一个最优稳定的解决方案,而是一些启发式方法。

在 AI 开发过程中,模型性能差常常源于不同的根本原因。鉴于机器学习模型的固有随机性,这很容易导致需要手动检查和验证的虚假发现。因此,即使一个切片发现技术可以产生理论上最优的结果,其结果仍必须经过人工检查和验证。为跨职能团队提供高效工具是许多机器学习团队的瓶颈。

我们已经指出,通常希望找到具有大支持的切片,但也希望从数据集基线中获得显著的模型性能差距。不同数据切片之间的关系通常是层次性的。在自动切片查找过程中和互动审查阶段处理这些层次结构是相当具有挑战性的。

自动切片查找方法在元数据丰富的问题上最为有效。这通常是实际问题的情况。相比之下,基准数据集在元数据方面总是相当稀疏。这主要有两个原因:数据保护和匿名化要求。由于缺乏合适的示例数据集,开发和展示有效的切片查找工作流变得非常困难。

我们(不幸地)必须在接下来的示例部分中处理这一挑战。

实践操作:在 CIFAR-100 上查找数据切片

CIFAR-100 数据集是一个成熟的计算机视觉基准。我们在本教程中使用它,因为它的体积小,易于处理,并且计算需求低。结果也易于理解,因为它们不需要特殊的领域知识。

不幸的是,CIFAR-100 已经非常平衡,经过高度整理且缺乏有意义的元数据。因此,我们在本节中生成的切片查找工作流的结果不如在实际环境中有意义。然而,所呈现的工作流应足以理解如何快速在实际数据中使用它们。

在准备步骤中,我们使用 Cleanvision 库计算图像元数据。有关此增强的更多信息,请参阅我们的 数据驱动 AI 操作手册

我们还定义了一些重要的变量用于数据切片分析:待分析的特征以及标签和预测列的名称:

大多数切片技术仅适用于分箱特征。由于 SliceLine 和 WisePizza 库本身不提供分箱功能,我们将其作为预处理步骤:

SliceLine

Sliceline 算法 是由 Sagadeeva 等人于 2021 年提出的。它旨在处理包含许多特征的大型表格数据集。它利用基于稀疏线性代数技术的新型剪枝技术,并允许在单台机器上快速查找数据切片。

在本教程中,我们使用 SliceLine 实现 来自 DataDome 团队。它运行非常稳定,但目前仅支持 Python 版本 <=3.9。

SliceLine 算法的大多数参数非常简单:切片的最小支持度 (min_sup)、定义切片的最大谓词数 (max_l) 和要返回的切片的最大数量 (k)。参数 alpha 为切片错误的重要性分配权重,并且基本控制切片大小与错误降低之间的权衡。

我们调用 SliceLine 库以获取 20 个最有趣的切片:

为了交互式探索切片,我们丰富了每个数据切片的描述:

我们启动 Spotlight 以交互式探索数据切片。你可以直接在 Huggingface 空间 体验结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:通过 SliceLine 生成的数据切片进行交互式探索。一个 互动演示 在 Huggingface 上可以使用。来源:作者创建。

我们发现 Sliceline 算法确实在 CIFAR-100 数据集中找到了有意义的数据切片。枫树柳树橡树 类别似乎存在问题。我们还发现,这些类别中具有较高 暗色评分 的数据点尤其具有挑战性。经过仔细检查,我们发现这是因为背景明亮的树木对模型来说很困难。

Wise Pizza

WisePizza 是 Wise 团队最近开发的工具。它旨在发现和可视化表格数据中的有趣数据切片。核心思想是使用 Lasso 回归为每个切片找到重要性系数。有关 Wise Pizza 工作原理的更多信息,请参阅 博客文章。

重要的是要注意,WisePizza 并不是作为机器学习调试工具开发的。相反,它主要旨在支持 EDA 过程中的分段分析。这就是为什么可以手动定义段候选项并为其分配权重。在我们的实验中,我们直接在数据集上运行 WisePizza,并将每个数据点的权重设置为 1:

为了探索我们非结构化数据集中的问题,我们以与 Sliceline 示例相同的方式提取问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4:WisePizza 还识别出柳树类别具有较大暗色评分的问题。然而,这些切片的细粒度不如 SliceLine 结果。来源:作者创建。

从图 4 中我们可以看到,在简单的 CIFAR-100 基准数据集上,WisePizza 找到了相关的片段:它还列出了带有高 dark scorewillow tree 类作为顶部切片。然而,以下结果仅限于不同的类别,并且不像 SliceLine 输出那样细粒度。一个原因是 WisePizza 算法没有直接提供切片支持和准确性下降之间的加权机制。

Sliceguard

Sliceguard 库使用 层次聚类 来确定可能的数据切片。然后,使用公平学习的方法对这些聚类进行排序,并通过可解释 AI 技术挖掘谓词。有关 Sliceguard 的更多信息可以在 这篇博客文章 中找到。

我们构建 Sliceguard 的主要原因是它不仅适用于表格数据,还能直接应用于嵌入。该库提供了大量内置功能用于预处理(如分箱)和后处理。

我们可以用几行代码在 CIFAR-100 上运行 Sliceguard:

Sliceguard 使用 Spotlight 提供识别的数据切片的互动可视化:

issue_df, issues = sg.report(spotlight_dtype={"image": Image})

Sliceguard 可以在 CIFAR-100 数据集上揭示细粒度的数据切片(图 5)。除了之前发现的树类数据切片外,我们还识别了其他问题(如 mouse 类)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5:Sliceguard 揭示了细粒度的数据切片。在 Huggingface 上提供了一个 互动演示。来源:作者创建。

结论

我们介绍了三种开源工具,用于挖掘数据切片。即使在简单的 CIFAR-100 基准上,它们也可以快速揭示关键数据片段。识别这些数据切片是理解模型失败模式和改善训练数据集的重要步骤。

SliceLine 工具适用于表格数据,并通过谓词组合描述数据切片。Sliceguard 不返回数学上保证的最佳谓词组合,但可以直接处理嵌入。此外,它可以在几行代码的基础上运行于非结构化数据集。

在实践中,SliceLine 和 Sliceguard 对识别数据切片非常有帮助。然而,这两种工具都不能用于完全自动化的切片分析。相反,它们提供了强大的启发式方法,可以与互动探索相结合。如果操作得当,这种方法是跨学科数据团队构建可靠 ML 系统的重要工具。

你是否有使用过展示的数据切割工具的经验,或者能否推荐其他开源库?我很乐意在评论中听到你的意见。

寻找改进的改写

原文:towardsdatascience.com/finding-improved-rephrasings-b5fb002ac811

使用带有机器学习元素的 Trie

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Arun Jagota

·发布于Towards Data Science ·19 分钟阅读·2023 年 4 月 19 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由Nile提供,Pixabay上可见

表达得好需要付出努力。幸运的是,体现现代自然语言处理的聊天机器人,如 ChatGPT,非常有帮助。

在这篇文章中,我们将使用适当增强的 Trie 来建模这个问题。这个 Trie 将自动检测在语料库中重复出现的短词序列,并且以无监督的方式进行。随后,它还将从标注的数据集(尴尬短语、改进短语对)中学习常见的“尴尬短语”模式。

对于小型但细微的改写问题版本,我们将展示通过在学习到的 Trie 上进行适当的模糊搜索,可以直接找到改进的表达方式。

对于更复杂的版本的问题,我们描述了一种使用 Trie 作为特征提取器的变体。这些特征可以集成到任何先进的神经语言模型中。

对于这个用途,Trie 需要进行特定的预处理和预训练。我们也将描述这两个步骤。

这种方法——本身——是…

  • 易于理解,无需具备神经网络或自然语言处理的背景知识。

  • 作为概念验证容易实现。

  • 独立有效于检测短小的尴尬短语并建议改写。

也许更重要的是,如上所述,这种方法允许将基于 Trie 的特征添加到现代神经网络模型中,这些特征建模了在语料库中重复出现的短序列,因此可能携带独特的语义。

本文中使用的单词序列示例,包括尴尬的短语和改进后的短语,都是 ChatGPT 在响应单个提示时提供的:

给我一些尴尬的短语示例,长度为两到四个词。

然后我选择了一个展示了本文方法所涉及的所有场景的子集。我将它们分配到本文的各个部分。这种分配是因为不同的表述展示了本文方法中的不同机制。

本文的最后部分列出了所有尴尬的表述及其改进后的表述。包括在 ChatGPT 的回复中未使用的那些,因为它们是其回复的一部分。

初步观点:问题框定为搜索

考虑她做饭好,我们希望更好地表达。假设我们有一个丰富且庞大的优质句子语料库进行学习。想象一下搜索以她做饭开头的句子。通过分析这些句子,我们可能会得出她做饭更好地表述为她做饭她做过饭

现在考虑第三个词good。语料库中可能没有与短语*(cooks|cooked) good*匹配的句子。

另一方面,我们可能会找到几个包含短语做饭很好的句子。凭借wellgood足够相似的额外知识,我们可能会倾向于建议她做饭很好作为更好的整体改写。我们可能从哪里获得这样的知识?词嵌入。

(我们在vectors.nlpl.eu/explore/embeddings/en/#输入了good,最强的“语义关联”是well,得分为 0.829。)

让我们将上述内容以流程的形式表达。

  1. 在我们的句子语料库中搜索那些以她做饭开头的句子。得到的最佳匹配是她做饭她做过饭

  2. 将匹配项替换到探测器中,即得到她做饭/做过饭好

  3. 接下来,搜索我们包含做饭/做过饭好的句子语料库。得到做饭很好作为一个好的匹配。在将其评分为好的匹配时,还要利用goodwell是语义关联的这一点,这可以通过比较它们的词嵌入来揭示。

  4. 将匹配项替换到转换输入的相关部分。我们得到她做饭很好

步骤 1 和 3 中的搜索需要有一定的模糊性,以找到不完全匹配。这些匹配项随后需要进一步后处理,以便提取它们之间的统计共性。

此外,请注意以下几点。在第 1 步中,第三个词good没有作用。这需要在预处理、搜索本身或结果的后处理过程中以某种方式发现。

同样,在第 3 步中,必须以某种方式忽略词。为什么?因为使用cooks/cooked good作为探测器而不是她做饭/做过饭好将更倾向于更好地概括。即使语料库中没有以她做饭很好开头的句子,最终的改写也可能会被建议。

上面两个段落讨论的要点可以用注意力机制来重新框定,这在大型语言模型中至关重要。

顺序特性

上述方法本质上是顺序的。我们从探针开始,检查其部分,适当地转换,然后重复。

在 Trie 上搜索

到目前为止,我们已经多次使用了“在句子语料库上搜索”这个术语。我们现在深入探讨一下如何进行这样的搜索。

我们将把句子语料库导入到一种叫做 Trie 的树数据结构中,然后在其上进行搜索。

那么,什么是 Trie?我们将通过一个示例来说明它,而不是给出定义。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:表示两个单词序列的 Trie。(作者提供。)

上述示例中的 Trie 表示以下两个句子的单词序列:狗追猫新工作很好

现在想象一下短语新工作好。我们可以直观地看到,这个短语映射到从 Trie 的根开始的路径,该路径标记为新工作很好

这种映射也被称为对齐,可以在下方表示。

 New  job      good
     |    |         |
The new  job  is  good

在这种方法中,找到表述的更好重述的问题变成了在 Trie 中找到与表述对齐的路径的问题。

让我们从更简单的情况开始,当存在从 Trie 的根开始的路径完全表示输入时。在图 1 中的 Trie 中,新工作很好 是这样一个输入的例子。

很容易看出,我们可以通过基于输入中的令牌进行从左到右的扫描来找到表示输入的路径。

现在考虑一个不太干净的探针:新工作好。在图 1 的 Trie 中没有完全对应于这个探针的路径。

处理第一个单词The缺失的一种方式是向 Trie 中添加跳过弧。下面是我们第一个图的一个版本,添加了几个跳过弧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:添加了一些跳过弧的 Trie。(作者提供。)

跳过弧使我们能够找到路径,其中某些元素在探针中缺失,但代价是消耗更多的空间并且搜索时间更长。

现在假设我们还知道一个新工作好的良好重述。我们可以将原始表述和改进的重述对视为一个标记实例。此外,假设我们以某种方式将重述与探针对齐,如下所示。

 New  job      good
     |    |         |
The new  job  is  good

现在我们有了一个标记的数据集,并且进入了监督学习的领域。

标记可能会产生显著的成本。那么,在我们的设置中,标签实际上能给我们带来什么?它们告诉我们在哪里添加跳过弧。

在这个特定的示例中,我们将在图 2 所示的位置添加两个跳过弧。

人们可能会问,为什么要使用跳过弧?为什么不直接进行前瞻搜索?

如果我们想处理多个连续缺失的标记怎么办?这是很可能的——我们很快会看到一个例子。我们需要一些大于 1 的正整数k的前瞻。k的值应该是多少?如果k仅比 1 稍大,我们不能处理许多连续缺失的标记,这种情况在现实中是很可能发生的。如果我们使用一个大的k,前瞻搜索可能会遇到组合爆炸,即不可扩展。这是因为我们必须搜索所有距离当前节点k范围内的可能后代。这些后代的数量可能随着k的增大而呈超指数增长。

跳跃弧的使用避免了这种组合爆炸。

对齐版本的标注实例精确地揭示了我们应该添加的跳跃弧。如下面的示例所示,有时我们想要学习跳过多个标记。

I     go         store.
 |     |            |
I will go to the  store

从这点出发,我们可以学会将跳跃弧从 Trie 节点[I, will, go]添加到节点[I, will, go, to, the]。这个跳跃弧将允许我们处理原始表述中相对于上述改进表述中缺失的to the

好吧,因此I go store将映射到从根节点发出的 Trie 上的特定路径。从这条路径中,我们需要读取序列[I, will, go, to the, store]。问题是,我们如何得到粗体部分?

我们可以做的一件事是为表示被跳过的标记序列的跳跃弧分配一个标签。当我们首次创建跳跃弧时,我们知道这个标记序列,因此可以立即设置标签。与主弧不同,跳跃弧的标签仅在构建改进的表述时使用,而不是在查找期间使用。正如我们所知,查找是跳跃。

这是半监督学习

好吧,我们已经看到在标注数据集上的训练是有价值的。我们还意识到,建立一个标签覆盖大多数干净句子的标注数据集可能是不可行的,比如维基百科。

我们如何利用大量语料库而不必从中推导出足够丰富的标注实例?简单。

  • 从语料库中学习 Trie 减去跳跃连接。这是无监督学习。

  • 从可能更小的标注数据集中学习跳跃连接。这是监督学习。

后者的基本假设是学习跳跃连接的问题具有普适性。我们确实在之前讨论的一个例子中看到了这种普适性。即使从一个标注实例中,我们也可以学会处理一个以The dog开头的句子在被损坏版本中The的缺失。

跳跃弧越接近根节点的泛化能力越强

看图 2。最接近 Trie 根节点的跳跃弧从根节点开始,跳过了The。这使得它能够考虑到任何以The开头的干净句子在任何被损坏版本中The的缺失。

现在考虑跳过句子中新工作是的跳过弧。这适用于更有限的句子集。

替代弧及其学习

为了激励这一点,我们将发现我们在帖子中覆盖的第一个重述示例是有用的。这涉及将她做饭好重述为她做饭好

好的,所以我们从根节点开始,越过标记为的弧。我们现在在节点[]上,但它没有子节点[做饭]。最接近的子节点是[做饭]。我们可以通过模糊匹配做饭做饭来找到这个子节点。我们应该记住,如果当前节点有许多子节点,找到最佳匹配的子节点可能需要时间。

对于这种模糊匹配的一种替代方法是从标记数据集中学习替代弧。

想象以下标记实例出现在监督训练集中。

She  cook   good
 |    |      |
She  cooks  well

我们可以想象从这个标记实例中学习,以添加我们所称的替代弧。这些在我们的示例中如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:添加了学习到的替代弧的 Trie。(作者提供。)

虽然图 3 没有显示这一点,但替代弧需要与主弧区分开,因为它们的使用方式略有不同。

在处理输入时,替代弧可能会被遍历。例如,在输入她做饭好时,我们会遍历标记为[做饭]的路径,其中第二个和第三个弧是替代弧。

从结果路径中得出的输出涉及将路径中的替代弧上的标签替换为对应的主弧。在我们的例子中,[做饭] 会被替换为 [做饭]。

替代弧与令牌的模糊匹配

正如我们在前一节中讨论的那样,只有在我们处于正确的左侧上下文时,令牌才会被模糊匹配。例如,考虑她做饭好,假设我们在节点她做饭。从这个节点发出的弧有一个标签。我们仅在这个左侧上下文她做饭中将匹配。这减少了假阳性的风险。

这意味着,使用模糊令牌匹配而不是替代弧不会增加风险。使用替代弧主要有助于加快匹配速度,当节点有许多子节点时尤其如此。模糊匹配替代方案要求我们找到来自父节点的所有弧上的标签,并将每个标签一个接一个地匹配到输入中的下一个令牌。

模糊匹配和替代弧都不一定假设匹配的令牌在词汇上相似,仅仅是它们在标记实例中对齐。

作为示例,考虑对齐情况

He  is    a   lawyer
|    |    |     |
He  is    an  attorney

律师法律顾问即使没有词汇上的相似性也是对齐的。

自弧及其学习

考虑表达方式You Like What及其改进的重述What Do You Like。重述涉及重新排列单词。我们希望继续利用字典树,而不是设计新的机制来处理单词顺序的重新排列。

想象一下,我们有一个标记和对齐的实例来表示这一对。

 You    like  what
         |      |
What do you    like

我们可以通过跳跃弧来建模改进的重述中的What do。要建模原始重述中的what,我们将使用自我弧的概念。

下面是建模这种情况的字典树的一部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4:具有自我弧(和跳跃弧)的字典树。(作者提供。)

让我们走查一下如何处理输入[you, like, what]。我们将从根节点开始,走跳跃弧,然后走标记为youlike的弧,最后走标记为what的自我弧。我们将连接路径上前三个弧的标签。我们将省略第四个弧的标签,因为我们知道它是自我弧。

减少构建标记和对齐实例的工作量

正如我们所见,标记的实例,即原始表达方式与改进的重述对齐的实例,在学习准确的重述建议模型中发挥着重要作用。我们标记实例的数据集越丰富,学习到的模型质量就越好。

鉴于此,我们可以减少构建标记实例的工作量吗?答案是可以。

以下我们提出一种方法,这种方法涉及将一个数据集中的序列(其中可能有许多尴尬的表达方式)对齐到一个在主要干净句子语料库上训练的字典树。接着,我们将描述如何利用某些经过充分论证的语言特征来增强这种方法。

用干净的字典树对齐不良序列

首先,假设我们有两个数据集,一个是相对干净的句子,另一个是质量较差的表达方式。想象一下,从第一个数据集中,我们按照前面描述的方式学习字典树。(这个字典树只有主要弧。)

现在考虑一个来自第二个数据集的实例——一个相对较差的实例。想象一下在当前字典树中找到一条从根节点开始并且与实例足够匹配的路径。通过这条路径结合实例,我们可以推导出我们所寻求的标记实例。

模糊匹配器需要如何工作?它需要使用前瞻操作来允许路径上的标记在探测器中缺失。它还需要使用模糊标记匹配来允许替换。

让我们说明这个过程。考虑下面的字典树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5:用于说明模糊匹配的字典树。(作者提供。)

现在考虑探测器Me go store。假设我们知道meI是语义关联词。我们将利用这一知识将meI对齐,然后进行一次前瞻,对齐gogo,再进行一次前瞻,最后对齐storestore。我们得到了所需的对齐。

如果我们认为这发生在离线训练阶段,那么模糊匹配甚至不需要进一步优化速度。前瞻可能需要时间,但这没关系。

有人可能会问,为什么不在推断时直接使用这种模糊匹配过程,而完全放弃监督训练?有两个原因。

首先,模糊匹配器可能运行较慢,因为它可能需要进行前瞻。一个慢的模糊匹配器在训练过程中比在推断过程中更可接受。

其次,允许从标记实例中学习允许将人工策划的标记实例与使用模糊匹配器自动生成的实例混合在一起。实际上,它甚至允许人工策划者丢弃那些被认为质量较低的自动生成实例。这可能仍然减少了获得一个同等丰富的数据集的整体努力,因为它自动化了发现过程。只要通过这种自动化过程找到的足够多的标记实例足够好,那么其好处可能会超过检测和标记假阳性的成本。

利用语言特征

这是基于这样的观察:在某些词性中,词语在不良表述中缺失的可能性比其他词性更高。例如,冠词或介词。以下是一些示例。

曝露阳光

他是律师

我们将这融入到我们将不良序列与干净 Trie 对齐的方法中,如下所示。

在第一步中,我们将不良序列与干净的 Trie 对齐。在这个过程中,不良序列x与 Trie 上的路径y对齐。对于y中的词序列,我们现在得到它们的词性。对齐现在不仅揭示了相对于y来说可能在x中缺失的词,还揭示了它们的词性。我们现在可以辨别出某些词性是否比其他词性更可能缺失。

在第 2 步中,我们穷举地列出 Trie 上的所有根到叶子路径,这可以通过深度优先或广度优先搜索等方式完成,并添加跳过弧以跳过在我们最易跳过的词性列表中的词。

让我们用一个简单的例子来说明。

比如我们将He is lawyerHe is a lawyer对齐。我们发现前者缺少一个冠词,在这种情况下是a。重复这个过程于许多不良序列应该能够辨别出冠词比其他一些词性更倾向于缺失。

更细粒度的变体

到目前为止,我们考虑的词序列用于输入 Trie 的都是语料库中的句子。这种选择是为了方便,因为将文本分割成句子相对容易。

在这一部分,我们考虑一个更细粒度的变体,其中我们输入到 Trie 中的词序列不一定是完整的句子,而是以某种主导顺序出现的词序列。

这种更细粒度的 Trie 有潜力建议句子中嵌入的较短单词序列的改进表述。

这是一个例子。没有人将skin cancer写作cancer skin。如果我们能够发现前者是这两个词的主导顺序,我们就可以检测到这种顺序的违规,并建议重新表述。

更为可信的情况是,当句子中的单词of the被错误地调换位置时,例如The top the of mountain

此外,也许更重要的是,这种更细粒度的 Trie 可以作为现代神经语言模型中的特征提取器,用于处理更复杂的拗口表述问题。实际上,对于大型语言模型适用的任何推断问题,包括语言生成,都是如此。

无论 Trie 是直接使用还是作为特征提取器,都需要解决一个新问题。即发现以某种主导顺序出现的单词序列。这个问题在我们的第一个 Trie 中不存在,因为句子被视为单词序列。

首先,以下术语将有所帮助。

可排序的袋子

如果一个单词多重集具有主导排序,我们将称之为可排序的袋子。

我们使用multiset这个术语而不是set,以允许同一个词出现多次。

例如,多重集{the, of}有一个主导排序[of, the]。

请注意,可排序的袋子与显著短语不同。前者只关心主导排序;后者还需要考虑显著性,即该短语传达的意义大于其部分之和。

从句子语料库中发现可排序的袋子

好了,现在让我们讨论如何从句子语料库中发现可排序的袋子。我们假设语料库中的所有句子都已经被分词为单词。

从这个语料库中,设想从所有长度至少为二的令牌序列中派生出一个数据集D1。接下来,我们将根据以下方式从D1 构建一个新的数据集D2。实际上,我们将把D2 解释为一个带标签的数据集。

对于每一个D1 中的序列y,在D2 中将有一个序列x,其中x是通过对y的单词进行词典顺序排序得到的。xD2 中的标签将是y。也就是说,我们用观察到的特定排序y来标记y的单词多重集。

下面是一个在D2 中的实例示例。

x = [cancer, skin], y = [skin, cancer]

我们将从D2 中的所有x构建一个 Trie。对于D2 中的任何一对(x, y),我们将把y作为卫星数据附加到 Trie 中x结束的节点上。

一旦 Trie 构建完成,我们将把 Trie 中各节点上的卫星数据压缩为两个属性。

  1. 作为标签的不同排序数量即在该节点结束的x

  2. 对于以 x 结尾的节点,这是一种关于所有排序的概率分布。为了紧凑地表示这种分布,我们将以如下所述的方式对排序进行编码。

我们将第一个属性——不同排序的数量——称为 支持度

当然,这个 Trie 可能非常庞大。但这对我们来说不是问题。

利用 Trie 发现顺序不当的子序列

考虑一个词序列,其中某些子序列的排序不当。例如 The top the of mountain

我们将通过枚举所有长度至少为 2 的子序列,按词典顺序对每个这样的序列进行排序,查找 Trie 中的该序列,并检查末尾节点是否具有揭示主要排序的卫星数据,从而发现不当措辞(如果有的话)。

示例

例如,一旦 Trie 构建完成,假设路径 [cancer, skin] 上的最右节点具有卫星数据 (520, [skin, cancer] → 1)。这仅表示包 {cancer, skin} 在数据集中被观察到 520 次,每次的排序为 [skin, cancer]。

在神经语言模型中使用可排序包 Trie 作为特征提取器

一旦可排序的包 Trie 构建完成,我们可以将其用作特征提取器,如下所示。

首先,让我们为 Trie 中的每条路径分配一个唯一的标识符。这个标识符将作为与该路径关联的特征值。

我们将一个词序列作为输入,并将其分割为 Trie 中的一系列最大路径,每个路径都是具有一定最小支持度的主要排序。为了涵盖所有情况,我们将由单个词组成的词序列定义为具有上述最小支持度的主要排序。

我们现在用它们的标识符替换这个序列中的路径。这样我们就得到了一个特征序列。对于这个序列中表示单词的路径,我们可以附加额外的特征,例如词嵌入。

让我们在下面的示例中说明这个过程。

考虑

曝露在阳光下会导致皮肤癌

想象一下,使用可排序包 Trie,我们将其分割为

exposure → to → sunlight, causes, skin → cancer

其在我们用 ids 替换路径后变为

pid1, pid(causes), pid2

从为我们的基于 Trie 的方法添加价值的角度来看,这一好处是显而易见的。现代神经语言模型具有令人印象深刻的能力。

在我们在此帖子中讨论的特定用例背景下,这将允许它们检测在较长文本部分(如段落或甚至多页)中需要改进的措辞。可能需要考虑长距离交互的措辞。

从为现代神经语言模型添加价值的角度来看,Trie 基础的特征将进一步丰富这些模型。基本的直觉是,某些短的词序列在文本中重复出现频繁,并且隐含地编码了特定的语义。

基于 Trie 的方法可以从语料库中自动发现这些序列,因此可以用于分析由这些序列的某些排列组成的更长序列。

让我们用一个简单的例子来说明。考虑

exposure to sunlight 导致 skin cancer

在这里,我们认为加粗的子序列是主导排序,并在我们的 Trie 中进行了表示。

我们可以想象,利用 Trie 的神经语言模型可以很容易地预测 exposure to sunlight causes 后面应该跟着 skin cancer

现在假设我们有一个标记的数据集,其中包含语义上等价的表述。作为这个数据集中的一个实例,考虑

{
  exposure to sunlight causes skin cancer, 
  skin cancer is caused by exposure to sunlight
}

从许多形式为 {X causes Y, Y is caused by X} 的实例中,并假设 XY 在 Trie 中被表示为主导排序路径,我们可以识别出这两者的语义等价性,并在某些推理或生成中使用这种学习。例如,如果我们被要求以不同的方式重新表达 X causes Y,我们可以回答 Y is caused by X

总结

在这篇文章中,我们讨论了发现尴尬表述——即词序列的排列——并提出改进方案的问题。

我们使用 Trie 对这个问题进行了建模。这个 Trie 可以以无监督的方式自动检测出语料库中重复出现的短词序列。Trie 中的一个监督机制还从标记数据集(包括(awkward phrasing, improved phrasing)对)中学习某些常见的“尴尬表述”模式。

对于小规模但细微的表述重述问题,我们展示了可以通过在学习到的 Trie 上进行适当的模糊搜索直接找到改进的表述。

对于问题的更详细版本,我们描述了一个变体,使用 Trie 提取高级重复特征,特别是短的重复词序列。我们推测为什么在最先进的神经语言模型中使用这些特征可以提高其准确性,并简化其训练。为此用途,需要对 Trie 进行某些预处理和预训练。我们也描述了这两者。

ChatGPT 中的短语

以下是 ChatGPT 在回复提示时提供的尴尬表述及其改进版本

给我一些长度为两到四个单词的尴尬表述的例子

在回复中,ChatGPT 将改进后的表述与尴尬的表述分开了。我为了读者的方便,将这些进行了对齐。

  • “Me go store.” 我要去商店

  • “You like what?” 你喜欢什么?

  • “Dog chase cat.” 狗在追猫。

  • “He no here.” 他不在这里。

  • “She cook good.” 她是个好厨师。

  • “Big house him.” 他有一栋大房子

  • “Funny joke that.” 那是个有趣的笑话

  • “Rain make wet.” 雨使一切变得湿润。

  • “Car go fast.” 这辆车正在快速行驶。

  • “New job good.” 新工作很好。

进一步阅读

  1. en.wikipedia.org/wiki/Sequence_alignment

  2. en.wikipedia.org/wiki/Trie

在干草堆中找针 — Jaccard 相似度的搜索索引

原文:towardsdatascience.com/finding-needles-in-a-haystack-search-indexes-for-jaccard-similarity-db1ccdaa8d17?source=collection_archive---------4-----------------------#2023-08-18

从基础概念到精确和近似索引

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Eric Zhù

·

关注 发表在 Towards Data Science · 15 分钟阅读 · 2023 年 8 月 18 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在干草堆中找针。图像由作者使用 Midjourney 制作。

向量数据库因作为大型语言模型(LLMs)的外部记忆而成为新闻话题。如今的向量数据库是建立在十年前的近似最近邻(ANN)索引研究基础上的新系统。这些索引算法处理许多高维向量(例如float32[]),并构建一个数据结构,支持在高维空间中找到查询向量的近似邻居。这就像 Google 地图根据你家的纬度和经度找到你邻居的房子一样,只不过 ANN 索引在更高维空间中操作。

这项研究有着几十年的历史。90 年代末,机器学习研究人员手工制作多媒体数据(如图像和音频)的数值特征。基于这些特征向量的相似性搜索成为一个自然的问题。一段时间内,研究人员涌入这一领域。这一学术泡沫在一篇开创性论文When is “Nearest Neighbor” Meaningful? 发表后破裂,基本告诉大家不要浪费时间,因为在手工制作特征的高维空间中的最近邻大多是不具有意义的——这是另一个话题。即便如此,我仍然看到研究论文和向量数据库基准测试发布关于 SIFT-128 数据集的性能数据,该数据集由具有无意义相似性的手工制作特征向量组成。

尽管手工制作特征存在噪声,但研究中有一条富有成果的方向专注于一种具有意义的高维数据类型:集合Jaccard

在这篇文章中,我将介绍集合上 Jaccard 相似性的搜索索引。我将从基本概念开始,然后转向精确和近似索引。

集合和 Jaccard

集合只是不同元素的集合。你在 Spotify 上喜欢的歌曲是一个集合;你上周转发的推文是一个集合;从这篇博客文章中提取的不同令牌也形成一个集合。集合是表示数据点的一种自然方式,适用于音乐推荐、社交网络和剽窃检测等应用场景。

假设在 Spotify 上,我关注了这些艺术家:

[the weekend, taylor swift, wasia project]

我的女儿关注了这些艺术家:

[the weekend, miley cyrus, sza]

衡量我们音乐品味相似性的一个合理方法是看我们共同关注了多少艺术家——即交集大小。在这种情况下,我们都关注了the weekend,所以交集大小为 1。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每个集合代表一个用户的关注列表。交集显示了两个用户共享的共同关注。图片由作者提供。

然而,你可以想象另一对用户每人关注 100 位艺术家,它们的交集大小仍然是 1,但他们的品味相似度应该远低于我女儿和我之间的相似度。为了使不同用户对之间的测量具有可比性,我们用并集大小来归一化交集大小。这样,我女儿和我关注的相似度为1 / 5 = 0.2,而另一对用户关注的相似度为1 / 199 ~= 0.005。这被称为 Jaccard 相似度。

对于集合A和集合B,Jaccard 相似度的公式是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

集合 A 和 B 的 Jaccard 相似度公式。

为什么集合是高维数据类型?集合可以编码为“one-hot”向量,其维度 1 对 1 映射到所有可能的元素(例如,Spotify 上的所有艺术家)。如果集合包含对应于该维度的元素,则该维度的值为 1,否则为 0。因此,我关注的艺术家的向量化集合如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

高维向量表示关注集合。图像由作者提供。

其中第二、第三和倒数第三个维度分别是the weekendtaylor swiftwasia project。Spotify 上有超过 1000 万的艺术家,因此这样的向量维度极高且非常稀疏——大多数维度为 0。

Jaccard 搜索的反向索引

人们希望快速找到事物,因此计算机科学家发明了被称为索引的数据结构,以使搜索性能对软件应用程序满意。具体来说,Jaccard 搜索索引是建立在一组集合上的,给定一个查询集合,它返回与查询集合具有最高 Jaccard 相似度的k个集合。

Jaccard 的搜索索引基于一种称为反向索引的数据结构。反向索引具有极其简单的接口:输入一个集合元素,比如the weekend,它返回包含输入元素的集合 ID 列表,例如[ 32, 231, 432, 1322, ...]。反向索引本质上是一个查找表,其键是所有可能的集合元素,值是集合 ID 列表。在这个例子中,反向索引中的每个列表表示一个艺术家的关注者 ID。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

反向索引包含与查询集合匹配的集合 ID 列表。图像由作者提供。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原始集合存储在一个单独的表中,以便通过其集合 ID 进行查找。图像由作者提供。

你可以看到这为什么被称为“反向索引”:它允许你从一个集合元素找到包含该元素的集合。

精确搜索算法

倒排索引是加速搜索的极其强大的数据结构。使用倒排索引时,在搜索时,你不需要遍历所有集合并与查询集合进行比较——如果你有数百万个集合,这会非常昂贵,你只需要处理与查询集合共享至少一个元素的集合 ID。你可以直接从倒排索引列表中获取集合 ID。

这个想法是通过以下搜索算法实现的:

def search_top_k_merge_list(index, sets, q, k):
    """Search top-k Jaccard using inverted index.

    Args:
        index: an inverted index, key is set element
        sets: a lookup table for sets, key is set ID
        q: a query set
        k: search parameter k

    Returns:
        list: at most k set IDs.
    """
    # Intialize an empty lookup table for candidates.
    candidates = defaultdict(0)

    # Iterate over set elements in q.
    for x in q:
        ids = index[x]  # Get a list of set IDs from the index.
        for id in ids:
            candidates[id] += 1  # Increment count for intersection size.

    # Now candidates[id] stores the intersection size of set with ID id.

    # A simple routine for calculating Jaccard using intersection size and
    # set sizes, based on Inclusion-Exclusion principle.
    jaccard = lambda id: candidates[id] / (len(q) + len(sets(id) - candidates[id]))

    # Find the top-k candidates order by Jaccard.
    return sorted(list(candidates.keys()), key=jaccard, reverse=True)[:k]

用通俗的语言来说,该算法遍历查询集合中元素匹配的每个倒排索引列表,并使用候选表跟踪每个集合 ID 出现的次数。如果一个集合 ID 出现了n次,则索引集合与查询集合有n个重叠元素。最后,算法使用候选表中的所有信息来计算 Jaccard 相似度,然后返回最相似的前 k 个集合的 ID。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

search_top_k_merge_list算法中的候选表用于跟踪通过倒排索引找到的索引集合的重叠计数。

当以下情况发生时,search_top_k_merge_list算法可以很快:(1) 查询集合中的元素数量较小,以及 (2) 查询元素的倒排索引列表中的 ID 数量较少。在 Spotify 场景中,如果大多数人关注的艺术家不多(可能是这样),并且所有艺术家拥有的粉丝数量大致相同(不准确)。我们都知道,少数顶级艺术家受到大多数人的关注,而大多数艺术家的粉丝很少。毕竟,音乐产业遵循帕累托分布

泰勒·斯威夫特在 Spotify 上有 7800 万粉丝,而周末(The Weekend)有 6700 万粉丝。将他们添加到我的关注列表中意味着search_top_k_merge_list算法需要遍历至少 1.45 亿个集合 ID,并且候选表candidates将增长到这个天文数字的规模。尽管今天的计算机速度快且强大,在我的 Intel i7 机器上,创建这样一个表仍然需要至少 30 秒(Python),并动态分配 2.5 GB 的内存。

大多数人关注一些超级明星艺术家。因此,如果你在搜索应用中使用这个算法,你肯定会因为大规模资源使用而获得一笔巨额的云托管账单,并且由于搜索延迟高,用户体验将会很差。

分支限界优化

从直观上看,之前的算法search_top_k_merge_list以广度优先的方式处理所有潜在候选,因为它仅使用倒排索引来计算交集。由于超级明星艺术家拥有数百万粉丝,这个算法表现不佳。

另一种方法是对潜在候选更加挑剔。假设你在面试候选人,你是招聘经理。你无法面试所有给你发送简历的潜在候选人,因此你根据招聘标准将候选人分到不同的类别中,并开始面试那些符合你最关心标准的候选人。随着你逐个面试,你评估每个人是否符合所有或大部分标准,当找到符合要求的人时停止面试。

这种方法在寻找类似的关注艺术家集合时也适用。这个想法是你希望从查询集中关注 最少粉丝数 的艺术家开始。为什么?因为这些艺术家提供的候选集较少,这样你可以处理更少的倒排索引列表,更快找到你最佳的 k 个候选。在我的 Spotify 关注列表中,wasian project 只有 100 万粉丝——远少于 taylor swift。那些关注 wasian project 的粉丝数量远少于关注 taylor swift 的粉丝,但他们有同样的潜力成为最佳 k 个候选。

这里的关键洞察是我们不希望处理所有潜在候选列表,而是在处理到足够数量时停止。棘手的部分是知道何时停止。以下是一个修改版的算法,实现了这个思想。

import heapq

def search_top_k_probe_set(index, sets, q, k):
    # Initialize a priority heap to store the current top-k candidates.
    heap = []

    # Initialize a set for tracking probed candidates.
    seen_ids = set()

    # Iterate over elements in q from the least to the most frequent based
    # on the lengths of their lists in the inverted index.
    for i, x in enumerate(sorted(q, key=lambda x: len(index[x]))):
        ids = index[x] # Get a list of set IDs from the index.
        for id in ids:
            if id in seen_ids:
                continue  # Skip seen candidate.
            s = sets[id]
            intersect_size = len(q.intersection(s))
            jaccard = intersect_size / (len(q) + len(s) - intersect_size)
            # Add the candidate to the priority heap.
            if len(heap) < k:
                heapq.heappush(heap, (jaccard, id))
            else:
                # Only candidates with higher Jaccard than the k-th
                # current candidate will be added in this operation.
                heapq.heappushpop(heap, (jaccard, id))
            seen_ids.add(id)
        # If any new candidate from the remaining lists cannot have higher
        # Jaccard than any of the current best k candidates, we do not need
        # to do any more work.
        if (len(q) - i - 1) / len(q) (<= min(heap)[0]:
            break

    # Return the best k candidates.
    return [id for _, id in heapq.nlargest(k, heap)]

search_top_k_probe_set 算法为它找到的每个新候选计算 Jaccard 相似度。它始终跟踪当前最佳的 k 个候选,并在任何新候选的上界 Jaccard 相似度不大于当前最佳 k 个候选的最小 Jaccard 相似度时停止。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

search_top_k_probe_set 算法遍历倒排索引列表,为每个遇到的候选集计算 Jaccard 相似度,并跟踪当前的 top-k 候选集。当未处理列表中任何集合的最大 Jaccard 相似度不大于当前 top-k 候选集的最小相似度时,它就会停止。图片由作者提供。

如何计算 Jaccard 相似度的上界?在处理了 n 个候选列表之后,对于任何未见候选,其与查询集的最大交集最多等于剩余未处理列表的数量:|Q|-n。我们给予它最大的怀疑,以便认为该候选可能出现在每一个剩余的 |Q|-n 列表中。现在我们可以使用简单的数学推导该候选 X 的上界 Jaccard 相似度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

计算一个未见候选索引集 X 和查询集 Q 之间 Jaccard 相似度的上界的公式,经过处理了 n 个候选列表之后。

这个巧妙的技术在集合相似性搜索研究文献中被称为前缀过滤器。我写了一篇论文,详细讲述了这一点以及进一步的算法优化。我还创建了一个 Python 库SetSimilaritySearch,实现了一个更优化的 search_top_k_probe_set 算法版本,并支持余弦和包含相似性度量。

Jaccard 搜索的近似索引

在最后一部分,我解释了两种基于倒排索引的搜索算法。这些算法是精确的,意味着它们返回的 k 个最佳候选项确实是最好的 k 个候选项。听起来老生常谈?其实,这是我们在设计大规模数据上的搜索算法时应该问自己的问题,因为在许多情况下,获取真实的 k 个最佳候选项并非必要。

再考虑一下 Spotify 的例子:你真的在乎搜索结果可能会遗漏一些与您品味相似的人吗?大多数人都明白,在日常应用程序(如 Google、Spotify、Twitter 等)中,搜索从来不会是详尽无遗或完全准确的。这些应用程序的任务并不足以证明精确搜索的必要性。这就是为什么最广泛使用的搜索算法都是近似的。

使用近似搜索算法主要有两个好处:

  1. 更快。如果你不再需要精确的结果,你可以省去许多步骤。

  2. 可预测的资源消耗。这一点不那么明显,但对于几种近似算法,它们的资源使用(例如内存)可以在事先配置,与数据分布无关。

在这篇文章中,我将讨论 Jaccard 最常用的近似索引:最小化局部敏感哈希(MinHash LSH)。

什么是 LSH?

局部敏感哈希索引在计算机科学中确实是奇迹。它们是由数论驱动的算法魔法。在机器学习文献中,它们被称为 k-NN 模型,但与典型的机器学习模型不同,LSH 索引对数据无关,因此它们在相似性条件下的准确性可以在事先确定,而不需要在摄取新数据点或更改数据分布之前进行调整。因此,它们更类似于倒排索引而不是模型。

LSH 索引本质上是一组具有不同哈希函数的哈希表。就像典型的哈希表一样,LSH 索引的哈希函数将一个数据点(例如,一个集合、特征向量或嵌入向量)作为输入,并输出一个二进制哈希键。除此之外,它们没有更多的相似之处。

典型的哈希函数输出的键在整个键空间中是伪随机且均匀分布的。比如,MurmurHash 是一个著名的哈希函数,它在 32 位键空间中输出近乎均匀且随机的哈希值。这意味着对于任何两个输入,例如 abcdefgabcefg,只要它们不同,它们的 MurmurHash 键就不应有相关性,并且在整个 32 位键空间中出现的概率应相同。这是哈希函数的一个期望特性,因为你希望键在哈希桶中均匀分布,以避免链表或不断调整哈希表的大小。

LSH 的哈希函数执行的是相反的操作:对于一对相似的输入,定义相似度的度量空间中,它们的哈希键更有可能相等,而不是另一对不相似输入的哈希键。

这意味着什么?这意味着 LSH 哈希函数对更相似的数据点具有更高的哈希键冲突概率。实际上,我们利用这一较高的冲突概率来进行基于相似度的检索。

MinHash LSH

对于每一个相似度/距离度量,有一个 LSH 哈希函数。对于 Jaccard,这个函数被称为 Minwise Hash FunctionMinHash function。给定一个输入集合,MinHash 函数使用随机哈希函数处理所有元素,并跟踪观察到的最小哈希值。你可以使用单个 MinHash 函数构建一个 LSH 索引。请参见下图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用单个随机哈希函数的 MinHash LSH 索引。图片来源于作者。

MinHash 函数背后的数学理论指出,两个集合具有相同最小哈希值(即哈希键冲突)的概率与它们的 Jaccard 相同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

h(A) 是通过随机哈希函数 h 对 A 中所有元素的哈希值。

min(h(A)) 是 A 中所有元素的最小哈希值。

这是一个神奇的结果,但证明却相当简单。

使用单个 MinHash 函数的 MinHash LSH 索引不能提供令人满意的准确性,因为碰撞概率与 Jaccard 成线性关系。请参见下面的图表以理解原因。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单个 MinHash 函数在查询集合和索引集合之间的 Jaccard 上的碰撞概率。Y 轴是碰撞概率,X 轴是查询集合和索引集合之间的 Jaccard。例如,Jaccard = 0.8 的索引集合与查询集合有 80% 的概率通过索引被检索到;而 Jaccard 为 0.2 的另一个索引集合与查询集合有 20% 的概率被检索到。图片来源于作者。

设想我们在 Jaccard = 0.9 处画一条阈值线:与查询集合 Jaccard 值高于 0.9 的结果是相关的,而 Jaccard 值低于 0.9 的结果是无关的。在搜索的背景下,“假阳性”意味着返回了无关的结果,而“假阴性”意味着没有返回相关的结果。根据上面的图,并查看假阳性对应的区域:如果索引只使用一个 MinHash 函数,它将产生非常高概率的假阳性。

提升 MinHash LSH 的准确性

这就是为什么我们需要另一个 LSH 魔法:一个叫做增强的过程。我们可以将索引提升到更符合指定的相关性阈值。

我们使用m个 MinHash 函数,这些函数通过称为Universal Hashing 的过程生成——基本上是 32 位或 64 位整数相同哈希函数的m个随机排列。对于每个被索引的集合,我们使用通用哈希生成m个最小哈希值。

设想你列出了一个索引集合的m个最小哈希值。我们将每r个哈希值分组到一个哈希值带中,我们创建b个这样的带。这需要m = b * r

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 MinHash LSH 中,具有 m= 16,b = 4 和 r= 4 的索引集合的最小哈希值。图片由作者提供。

两个集合具有“带碰撞”的概率——两个集合中的所有哈希值在一个带中碰撞,或r个连续的哈希碰撞,是Jaccard(A, B)^r。这比单个哈希值小得多。然而,两个集合之间至少有一个“带碰撞”的概率是1 — (1-Jaccard(A, B)^r)^b

我们为什么关心1 — (1-Jaccard(A, B)^r)^b?因为这个函数有一个特殊的形状:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用 b = 32 和 r = 32 的 MinHash LSH 索引的 Jaccard 检索增强概率函数。图片由作者提供。

在上面的图中,你可以看到使用m个 MinHash 函数时,“至少一个带碰撞”概率是一个 S 型曲线函数,在 Jaccard = 0.9 附近急剧上升。假设相关性阈值为 0.9,则该索引的假阳性概率远小于仅使用一个随机哈希函数的索引。

因此,LSH 索引总是使用br个 MinHash 函数的带来提升准确性。每个带是一个存储指向索引集合的指针的哈希表。在搜索过程中,任何与查询集合在任何带中碰撞的索引集合都会被返回。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个使用 b = 4 和 r = 4 的 MinHash LSH 索引。每个带是一个哈希表,其哈希键是 4 个 MinHash 函数的最小哈希值的连接。图片由作者提供。

要构建 MinHash LSH 索引,我们可以指定一个先验的相关性阈值以及基于 Jaccard 相似度的可接受的假阳性和假阴性概率,并在索引任何数据点之前,计算最优的mbr。这是使用 LSH 相对于其他近似索引的一个巨大优势。

你可以在 Python 包datasketch中找到我的 MinHash LSH 实现。它还包括其他与 MinHash 相关的算法,如 LSH 森林和加权 MinHash。

最终思考

我在这篇文章中涵盖了很多主题,但我只是浅尝辄止地探讨了 Jaccard 相似度搜索索引。如果你有兴趣阅读更多这些主题,我为你准备了进一步阅读的列表:

那么嵌入呢?

近年来,由于使用像 Transformers 这样的深度神经网络在表示学习上的突破,当输入数据属于嵌入模型训练的相同领域时,学习到的嵌入向量之间的相似度是有意义的。与本文描述的搜索场景相比,这种情况的主要区别在于:

  • 嵌入向量是通常具有 60 到 700 维的稠密向量。每一维都是非零的。相比之下,集合在表示为独热编码向量时是稀疏的:10k 到数百万维,但大多数维度为零。

  • 余弦相似度(或标准化向量上的点积)通常用于嵌入向量。对于集合,我们使用 Jaccard 相似度。

  • 很难为嵌入向量之间的相似性指定一个相关性阈值,因为这些向量是对原始数据(如图像或文本)的黑箱表示。另一方面,集合的 Jaccard 相似度阈值要容易得多,因为集合是原始数据

由于上述差异,比较嵌入和集合并不是直接的,因为它们是明显不同的数据类型,即使你可以将它们都归类为高维数据。它们适用于不同的应用场景。

使用分支定界找到最佳解决方案

原文:towardsdatascience.com/finding-optimal-solutions-with-branch-and-bound-70a64692a0dd

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Robocat 和猫咪一起玩耍。图像由作者使用 Dall·E 创建。

解决离散优化问题的强大算法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Hennie de Harder

·发表于 Towards Data Science ·阅读时间 8 分钟·2023 年 12 月 5 日

分支定界是许多混合整数规划 (MIP) 求解器的核心算法。它是你数学优化工具包中的一项极佳补充,特别适用于较小的问题或有许多约束的问题。此外,它的直接性使得它易于访问,无需复杂的数学公式。

在这篇实用文章中,我们将深入探讨一个数学优化问题。我们将使用分支定界算法来解决这个问题,这是一种解决此类问题的优秀技术。我们将重点讨论一个以猫为主题的问题——因为说实话,谁不喜欢猫呢?不过,如果你更喜欢狗,可以在讨论中每次遇到‘猫’时,脑补成‘狗’。原理和方法完全相同!

问题介绍

假设你是一个猫庇护所的主人。每天,宠物主人可以带他们的猫来你这里,你负责照顾它们。许多人在 COVID 期间领养了猫,但现在大家都需要回到办公室。这就是你公司的业绩蒸蒸日上的原因。

实际上,有些过于出色。你在将所有猫安置到你建筑中的房间时遇到了困难。有时你不得不拒绝人们的请求,因为要求太多了。这就是为什么你决定创建一个优化算法,以帮助你找到所有猫登记的最低房间数。

让我们来看一个例子。假设有 3 只猫请求入住你的庇护所。它们的名字是 Lily、Charlie 和 Meowster。我们该如何将这三只猫分配到不同的房间中?我们最多需要三个房间,以下是分组猫咪的所有可能方案:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

猫的分割。图片由作者提供。

分割和贝尔数

如你所见,将 3 只猫分组有 5 种可能的方法。在数学中,分组集合元素的一种方式被称为分割贝尔数对应于给定集合(在我们的例子中,即 3 只猫可以创建 5 种分割)的所有可能分割的总数。这来自组合数学领域。

计算下一个贝尔数的递归公式如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

计算贝尔数的递归公式。图片由作者提供。

这个数字增长很快:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

贝尔数和不同集合大小的计算。图片由作者提供。

一个问题出现了:我们如何以智能的方式找到所需房间的最小数量?当猫的数量增加时,循环遍历所有可能的解决方案是没有意义的。这将耗费大量时间。

从问题到树

首先,让我们重新表述问题。然后,我们将使用分支限界算法解决它。

我们可以从没有猫开始,然后一个一个地添加所有猫,而不是创建所有可能的解决方案并计算它们的分数(我们使用了多少房间)。这看起来像一棵带有节点和边的树:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解决方案树。在每一行中增加一只猫。这给我们所有可能的分割。图片由作者提供。

你是否看到了如何在一只新猫(元素)到来时创建所有可能的解决方案(分割)?让我们再增加一只猫:Pawsanova。这很简单,因为我们可以将它添加到所有现有的组中,并作为每个分割中的一个单独组。这对应于图片中的红点:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

再增加一只猫,Pawsanova。可以在 15 个位置‘插入’它。图片由作者提供。

对于第四只猫,共有 15 种可能的分割方式。这对应于 4 个元素集合的贝尔数。

在使用分支限界算法解决问题时,我们将使用这个包含可能解决方案的树。

分支限界

现在我们从原始问题创建了一个树,我们可以利用这个树来运行分支限界算法。分支限界是如何工作的?直观地说很简单:

分支限界将问题分解成更小、更易于管理的子问题(分支),然后为这些子问题确定界限,以有效地找到最优解。

分支

将问题分解成更小的子问题正是我们通过创建一个猫的树所做的。我们从没有猫开始,根节点,然后一个一个地添加猫。每个子问题由树的一个节点表示。

界限

分支限界的一个重要部分是确定问题的界限。它是这样工作的:

  • 上界与目前为止找到的最佳分数相对应。

  • 下界 是我们在继续当前树分支时可以找到的最佳分数。这是一个乐观的分数,计算时间不应过长。

剪枝

通过将当前节点的下界上界进行比较,我们可以决定是否继续搜索树的当前部分。如果下界比上界差,我们可以丢弃这部分树。通过丢弃那些不能产生更好解决方案的子问题,算法减少了需要检查的解决方案数量。这个过程被称为剪枝,对算法的效率至关重要。

另一种剪枝树的方法是检查当前子问题是否可行。例如,如果我们已经知道两只猫不能待在一个房间里,因为它们都是急躁的,而当前节点将这两只猫组合在一起,那么我们也可以剪枝这部分树。

探索方法

探索树以找到最佳解决方案有多种方法。你可能对深度优先搜索(DFS)和广度优先搜索(BFS)有所了解。深度优先搜索会尽可能深入地探索一条分支。广度优先搜索则会探索当前深度的所有节点(逐个添加猫,就像我们创建树时做的那样)。另一种策略是最佳优先搜索,这种方法根据某些标准(如优化问题中的下界)对节点进行优先级排序。下面你可以看到 BFS 和 DFS 的区别(查看节点序号以了解顺序):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

广度优先搜索和深度优先搜索。图片由作者提供。

解决猫问题

了解这些知识后,让我们回到最初的问题。让我们在 Python 中实现分支限界法。我们将使用广度优先搜索,但可以随意重用这段代码以尝试其他探索策略。

我们将实现的一些规则:

  • 解决方案的分数将等于我们使用的房间数量。显然,我们希望将其最小化。

  • 可行性:一个房间不能有超过 5 只猫,房间内猫的总重量不应超过 25 公斤。此外,一个房间最多只能有一只‘生气’的猫,否则我们会有猫打架…

  • 节点的下界通过当前节点的分数加上基于愤怒猫数量所需的最小额外房间数来计算。

注:你只需安装numpy包。

让我们从一个Cat类开始。

使用generate_n_cats函数,我们可以生成任意数量的猫。

在接下来的代码片段中,我们将实现分支限界算法:

branch_and_bound.py文件包含两个类:Node类和BranchAndBound类。

Node 类包含树中一个节点所需的所有信息。它有一个 partition 属性,你可以在这里找到该节点的猫分组。类中的方法用于计算权重、愤怒猫的数量、该节点的下界和可行性检查。

BranchAndBound 包含该算法。它从一个有效的解决方案(所有猫在分开的房间)开始,并计算该解决方案的得分作为上界。然后,它从没有猫开始,一只一只地添加猫。它添加新的节点,并通过检查可行性和比较下界与上界来判断是否可以剪枝。

这是处理 15 只猫的结果示例:

Score of Branch and Bound: 5
Time of Branch and Bound: 0.03134322166442871
[Cat(name=cat_0, weight=1, character=angry)]
[Cat(name=cat_1, weight=4, character=angry)]
[Cat(name=cat_7, weight=6, character=angry), Cat(name=cat_8, weight=1, character=sweet), Cat(name=cat_9, weight=8, character=sweet), Cat(name=cat_10, weight=6, character=sweet), Cat(name=cat_11, weight=1, character=sweet)]
[Cat(name=cat_2, weight=6, character=sweet), Cat(name=cat_4, weight=7, character=angry), Cat(name=cat_5, weight=4, character=sweet), Cat(name=cat_6, weight=6, character=sweet), Cat(name=cat_12, weight=1, character=sweet)]
[Cat(name=cat_3, weight=8, character=angry), Cat(name=cat_13, weight=4, character=sweet), Cat(name=cat_14, weight=1, character=sweet)]

该算法创建了 5 个组,每组最多有 5 只猫,最多 1 只愤怒的猫,且总重最多为 25 公斤。此外,该算法非常快速,找到(其中之一)最优解的时间不到 0.032 秒。第 15 个贝尔数接近 14 亿,想象一下,如果我们循环遍历所有 14 亿个可能的分区需要多长时间!

优缺点

分支限界法是一个容易理解的算法。树的剪枝使得它比动态规划或暴力破解等算法更高效,因为它跳过了那些不感兴趣的解决方案。分支限界法保证找到最优解,这是一个巨大的优点。但当然,也有缺点。如果我们将算法优化为处理 50 只猫而不是 15 只,它将需要很长时间来运行。在 50 只猫的情况下,树有许多节点且非常深。为了提高效率,我们可能需要考虑其他算法,例如元启发式算法。这里要注意的是,下界计算的强度对性能有很大影响。越严格越好,但确保它确实是下界(不高于该分支的实际最佳解决方案)。而且,针对你的具体问题,尝试不同的探索方法可能会有价值。在猫的例子中,我们从一个不好的初始解决方案(所有猫在不同的房间)开始,而从一个好的解决方案(例如,如果猫能适应,则贪婪地将猫添加到现有房间)开始更好。这可以加快算法的运行速度。

结论

希望你喜欢这个猫收容所的故事!现在你知道了分支限界法是如何工作的,也学到了一些组合数学的知识,比如分区和贝尔数。分支限界法是离散优化问题中使用的一种基本技术。许多 MIP 求解器将分支限界法作为其核心算法。通过剪枝,你不必遍历所有可能的解决方案。这节省了很多时间,但要小心,对于具有大型解决方案树的问题,它仍然可能需要(过于)长的时间。

感谢阅读,下次见!

相关内容

## 为什么每个数据科学家都应该学习数学优化

数据科学课程专注于数据可视化、特征工程、数据处理、(非)监督学习…

towardsdatascience.com ## 每个数据科学家应该了解的数学优化启发式方法

局部搜索、遗传算法等。

towardsdatascience.com ## 如何处理优化问题?

简单的例子和解决方案以及代码。

towardsdatascience.com

利用多项式混沌扩展、使用 uncertainpy 和 chaospy 寻找混乱中的秩序

原文:towardsdatascience.com/finding-order-in-chaos-with-polynomial-chaos-expansion-using-uncertainpy-and-chaospy-a66487f330c7?source=collection_archive---------6-----------------------#2023-10-12

下面是如何利用数学、物理学、Python 和数据科学来解决混乱问题的方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Piero Paialunga

·

关注 发布在 Towards Data Science ·9 min read·2023 年 10 月 12 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者使用 Midjourney 生成

三年前,我从意大利罗马搬到了美国俄亥俄州辛辛那提,接受了辛辛那提大学的博士 offer。我非常怀念我的城市,有很多东西:美食、天气、永恒之城的美丽。我绝对不怀念我城市的一件事是疯狂的交通

我的一个好朋友前几天给我发了短信说

“皮耶罗,今天交通太糟糕了,城市一片混乱。”

现在,显然,我没有纠正他(尤其是知道罗马的交通情况),但术语混乱在数学和物理中有着与我们日常生活中使用的“混乱”完全不同的意义。

当我们谈到数学中的混乱时,一个流行的定义是:一个由确定性方程控制的问题, 系统的演变极度依赖于初始条件。这意味着即使初始条件发生极其微小的变化,系统的演变也可能会极其不同。用洛伦茨¹的话来说,这意味着:

“现在决定未来,但近似的现在不能近似决定未来。”

¹ mpe.dimacs.rutgers.edu/2013/03/17/chaos-in-an-atmosphere-hanging-on-a-wall/

这意味着我们能够预测状态的演变的唯一方法是从概率视角考虑它。给定过程的起始点,我们无法准确预测系统的到达点,因为它是混乱的,但我们能够概率性地预测,比如我们可以得到平均值和初始偏差。

这种混乱可以通过数值方法处理,例如使用Python。在这篇博客文章中,我们将从抽象的随机游走开始,描述多项式混沌展开(PCE),并应用于一个实际案例,如我们的咖啡温度☕️。

让我们开始吧!

1. 随机游走

随机游走是所有阅读的数学家和物理学家都很熟悉的东西。这个模型几乎在所有地方都被使用,从金融到物理,它非常简单。它在文献中也被称为布朗运动,其工作原理如下:

  1. 我们从点 x = 0 开始

  2. 以相同的概率,我们可以从 x=0 到 x=1,或者从 x=0 到 x=-1。我们将这个点定义为 x_1

  3. 再次,我们可以将 x_1 的值增加或减少 1。我们将定义这一点为 x_2。

  4. 我们用 x_2 重复第 3 点 N-2 次

有时候,我觉得伪代码比用文字解释更容易理解

RandomWalk(N):
  x = 0
  i = 0 
  while i<N:
    p = random(-1,1)
    x = x+p
    i = i+1
  return x 

现在我们来探讨一下这个问题,好吗?

1.2 代码

在这一部分中,我们将使用 Python 语言代码描述随机游走。你需要导入像numpymatplotlib.pyplot这样的基本库。

这是随机游走代码:

如果我们运行这个,比如 100 次,我们会得到以下路径:

很有趣的是,如果你考虑最后一步,你可以发现高斯分布

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们先留在这里。我保证,我们会用到这些。

2. 微分方程

现在,关于生活的一切,等一下,字面上,我们所知道的关于生活的一切都是因为微分方程

微分方程是物理学用来描述系统演变的工具。我的高中老师通过这样解释:

“描述世界你需要两样东西:区分和积分。区分非常容易,积分非常困难。”

例如,让我们考虑爬树的松鼠的y位置:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者使用 Midjourney 生成

假设松鼠的速度是 v(t) = (t/60)2,其中 t = 秒。所以我们的超级英雄开始时的 v(t=0) = 0,经过两分钟,他的速度达到 v(120) = 22 = 4 m/s。

给定这些信息,超级松鼠的位置在哪里?

我们需要做的是积分速度方程,然后得到:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们如何得到这个 c 常数?我们只是设置 t = 0 时发生的情况。我们假设我们的松鼠从高度 = 0 开始,所以 c = 0。

所以我们爬树的超级松鼠的位置如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通常,一个特定的解决方案 y 可以看作是另一量,例如 x 的积分以及一个初始条件。

在这个方案中,我们讨论了:

  • 时间(t),这是时间变量(从实验开始到结束)

  • x,即我们正在积分的对象(在上述例子中,x是速度)

  • 解决方案(y)是我们通过积分x得到的解决方案(在上述例子中,y是超级松鼠的位置)

所以在这种情况下,我们可以说 x (t) = y(t) 的积分。

还有更多。你可以在系统中拥有一些固定的参数,但这些参数可以改变系统的演变。 所以:

x(t, 参数列表) = y(t, 参数列表) 的积分

例如。我们来谈谈咖啡。咖啡?是的,咖啡。

2.1 牛顿的冷却定律

一位在物理学上相当出色(哈哈)的家伙,名叫艾萨克·牛顿,在他留给我们的众多礼物中,解释了如何描述热体的热传导。换句话说,他告诉我们物体如何冷却。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者使用 Midjourney 生成

牛顿提出的冷却定律指出,从身体到外界的热量流失速率与一个常数 k 成正比,该常数依赖于表面积及其热传导系数,以及时间 t 的温度 T 和环境温度 T_env 之间的差异。

如果我们想获得温度(T),我们需要积分热量流失速率(dT/dt)这是方程:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供

要获得温度 T,给定 T_env 和 k(记住这一点!!!),我们需要积分 dT/dt。

3. 威纳的混沌!

我们非常罕见地能够定义微分方程的解析解。这就是我高中教授说它很难积分的原因。我们更可能需要进行数值积分,即用数值方式(也就是用算法)解决微分方程。

有一些非常著名的积分方法(算法),比如梯形规则黎曼和。它们有效,有利有弊,并且高效。它们不是问题所在。

真正的问题在于微分方程的参数(例如 T_env 和 kappa)。让我详细说明一下。

你还记得上面方程中的T_envk吗?我们完全不知道它们实际是什么,它们可能会完全改变我们系统的演化。

诺伯特·维纳的美丽心灵为带有额外随机参数的微分方程提供了非常优雅的公式。特别是,现在我们所有的讨论都很有意义了,带有随机参数的微分方程被定义为混沌的,可以用随机游走(啊哈!)作为多项式来描述。通过这样做,我们能够以概率方式理解解 T(t)!

我理解这可能会让人困惑:让我们一步一步来 😃

3.1 设置

我们在 Python 中需要做的第一件事是定义我们的微分方程:

如我们所见,这不仅仅是T(我们的变量)的问题,还有kappa 和 T_env的问题。

这是我们需要积分的函数。在此之前,让我们导入一些朋友🦸‍♂️

你可能会遇到错误,因为你没有chaospy 和 uncertainpy。它们是我们的魔法小助手:它们实现了多项式混沌展开方法。安装它们非常简单:

pip install uncertainpy

3.2 积分函数

让我们使用梯形规则设置需要积分的函数:

所以:

  • 我们设定咖啡的初始温度,比如 T_0 = 95

  • 我们设定我们问题的时间步长,比如 500 个时间步

  • 我们使用梯形规则进行积分

  • 我们返回时间和温度

3.3 关于 uncertainpy

现在,我得说一下:uncertainpy 非常棒。你可以用它做很多事情,我真的推荐你花时间在这里了解一下。

我们要做的是:

  • 我们设定一个可能的kappa分布。例如,kappa 从具有给定 mu 和方差的正态分布中抽取。

  • T_env做同样的处理

  • 我们应用 uncertainpy 并提取给定输入分布的温度可能值分布

游戏很简单:如果我们知道得益于 Wiener 的混沌参数的可能分布,我们就能知道输出的分布。

这可能听起来有点混乱,但我保证展示代码后会更清楚:

模型通过coffee_cup定义,这就是我们的微分方程。接着,我们定义参数分布(使用chaospy)并定义相应的参数字典。

现在。对于每个 kappa 和 T_env 值,我们有一个具有不同参数和不同温度 T(t) 的微分方程,这些是积分的结果。得益于神奇的chaospy,解决方案变成了一个具有均值和标准差的分布

让我们看看如何操作:

就是这样!(就像 Biggie 所说)。非常简单。

3.4 整体内容

整个内容可以放在这个代码块中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这难道不美好吗?我们能够将输入参数的分布转化为输出结果的分布。在时间 t=0 时,温度是 T= T_0 = 95。随着时间的推移,参数的不确定性变得越来越明显。在时间 = 200 分钟时,我们有一个很大的不确定性(假设从 5 到 30),这取决于 k 和 T_env,可能会很冷或稍微有点热。

4. 结果

在这篇博客文章中,我们描述了美妙的chaospy 和 uncertainpy 库。这些库使我们能够处理Wiener 混沌问题,它使用随机游走来定义一种多项式混沌。这种多项式混沌用于处理带有分布的微分方程,而不是参数。我们按以下顺序进行了操作:

  • 我们在第一章中描述了随机游走

  • 我们在第二章中描述了微分方程。特别是我们描述了牛顿冷却定律。

  • 我们按照Wiener的描述了混沌并在第三章中应用了多项式混沌

5. 结论

如果你喜欢这篇文章并想了解更多关于机器学习的内容,或者你只是想问我一些问题,你可以:

A. 在 Linkedin 上关注我,我会发布所有的故事。

B. 订阅我的 通讯。它将让你了解新故事,并给你机会与我联系,获取所有可能的更正或疑问。

C. 成为一个 会员,这样你就不会有“每月故事的最大数量限制”,可以阅读我(以及成千上万其他机器学习和数据科学顶级作者)写的关于最新技术的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值