热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

排序np_数据科学家的排序技巧

原题|SurprisingSortingTipsforDataScientists作者|JeffHale原文|https:towardsdatascience.comsurpris

原题 | Surprising Sorting Tips for Data Scientists

作者 | Jeff Hale

原文 | https://towardsdatascience.com/surprising-sorting-tips-for-data-scientists-9c360776d7e

声明 | 翻译是出于交流学习的目的,欢迎转载,但请保留本文出处,请勿用作商业或者非法用途

导读

这篇文章介绍了 Python 中几个常用库的排序技巧,包括原生 Python的、Numpy、Pandas、PyTorch、TensorFlow 以及 SQL。

前言

现在其实有很大基础的排序算法,其中有的算法速度很快而且只需要很少的内存,有的算法更适合用于数据量很大的数据,有的算法适合特定排序的数据,下面的表格给出了大部分常用的排序算法的时间复杂度和空间复杂度:

3c46c0bb95e8b93fc9fc6d81366e4cae.png

对于大部分数据科学问题,并不需要精通所有排序算法的基础实现。事实上,过早进行优化有时候会被认为是所有错误的根源。不过,了解哪个库以及需要使用哪些参数进行排序是非常有帮助的,下面是我做的一份小抄:

e6e4ec09618b0789784f109820c0739b.png

接下来将分别介绍上述这几个库的排序方法,不过首先是介绍本文用到的这几个库的版本,因为不同版本的排序方法可能会有些不同:

python 3.6.8
numpy 1.16.4
pandas 0.24.2
tensorflow==2.0.0-beta1 #tensorflow-gpu==2.0.0-beta1 slows sorting
pytorch 1.1

Python

Python 包含两个内置的排序方法:

  • my_list.sort() 会修改列表本身的排序顺序,应该它返回值是 None
  • sorted(my_list) 是复制一份列表并进行排序,它不会修改原始列表的数值,返回排序好的列表。

sort 方法是两者中速度更快的,因为是修改列表本身的关系。但这种操作是非常危险的,因为会修改原始数据。

两种排序方法的默认排序方式都是升序--由小到大。大部分排序方法都可以接受一个参数来改变排序方式为降序,不过,不幸的是,每个库的这个参数名字都不相同。

在 python 中,这个参数名字是 reverse,如果设置 reverse=True 表示排序方式是降序--从大到小。

key 也是一个参数名字,可以用于创建自己的排序标准,比如sort(key=len) 表示根据元素的长度进行排序。

在 python 中的唯一排序算法是TimsortTimsort是源自归并排序和插入排序,它会根据需要排序的数据的特征选择排序方法。比如,需要排序的是一个短列表,就选择插入排序方法。更详细的Timsort实现可以查看 Brandon Skerritt 的文章:

https://skerritt.blog/timsort-the-fastest-sorting-algorithm-youve-never-heard-of/

Timsort是一个稳定的排序算法,这表示对于相同数值的元素,排序前后会保持原始的顺序。

对于 sort()sorted() 两个方法的记忆,这里提供一个小技巧,因为sorted() 是一个更长的词语,所以它的运行速度更长,因为需要做一个复制的操作。

Numpy

Numpy 是 Python 用于科学计算的基础库,它同样也有两个排序方法,一个改变数组本身,另一个进行复制操作:

  • my_array.sort() 修改数组本身,但会返回排序好的数组;
  • np.sort(my_array) 复制数组并返回排序好的数组,不会改变原始数组

下面是两个方法可选的参数:

  • axis 整数类型,表示选择哪个维度进行排序,默认是 -1,表示对最后一个维度进行排序;
  • kind 排序算法的类型,可选为 {quicksort’, ‘mergesort’, ‘heapsort’, ‘stable’},排序算法,默认是快速排序--quicksort
  • order 当数组 a 是定义了字段的,这个参数可以决定根据哪个字段进行比较。

不过需要注意的是这个排序算法的使用和对这些参数名字的期待会有所不同,比如传递kind=quicksort实际上采用的是一个 introsort 算法,这里给出 numpy 的文档解释:

当没有足够的进展的时候,会转成堆排序算法,它可以让快速排序在最糟糕的情况的时间复杂度是 O(n*log(n))stable会根据待排序数据类型自动选择最佳的稳定排序算法。而如果选择 mergesort 参数,则会根据数据类型采用 timsort 或者 radix sort 。因为 API 的匹配性限制了选择实现方法并且也固定了对不同数据类型的排序方法。Timsort是用于排序好的或者接近排序好的数据,对于随机排列的数据,它的效果几乎和 mergesort 一样。目前它是作为排序算法,而如果没有设置 kind 参数,默认选择还是快速排序quicksort ,而对于整数数据类型,'mergesort' 和 'stable' 被映射为采用 radix sort 方法

上述来自 numpy 的文档解释,以及作者的部分修改:

https://github.com/numpy/numpy/blob/v1.16.1/numpy/core/fromnumeric.py#L815-L935

在上述介绍的几个库中,只有 numpy 是没有可以控制排序方式的参数,不过它可以通过切片的方式快速反转一个数组--my_arr[::-1]

numpy 的算法参数在更加友好的 pandas 中可以继续使用,并且我发现函数可以很容易就保持。

Pandas

Pandas 中对 DataFrame 的排序方法是 df.sort_values(by=my_column) ,参数有:

  • by:str 或者是 list of str ,必须指定。根据哪个或者哪些列进行排序。如果参数axis 是 0 或者 index ,那么包含的就是索引级别或者是列标签。如果 axis 是 1 或者 columns ,那么包含的就是列级别或者索引标签。
  • axis :{0 or index, 1 or columns},默认是 0。排序的轴
  • ascending: bool 或者list of bool 。默认是 True 。排序方式,升序或者降序,可以指定多个值,但数量必须匹配 by 参数的数量。
  • inplace:bool ,默认是 False 。如果是真,那就是修改本身数值,否则就是复制一份;
  • kind:{quicksort, mergesort, heapsort, stable},默认是 quicksort。排序算法的选择。详情可以看看numpyndarray.np.sort 。在 pandas 中这个参数只会在对单个标签或者列中使用
  • na_position:{'first', 'last'} 。默认是 'last' 。这是指定 NaN 放置的位置,first 是将其放在开头,last 就是放在末尾。

对于 Series 类似也是同样的排序方法。但Series 并不需要指定 by 参数,因为不会有多列。

由于底层实现是采用 numpy ,所以同样可以得到很好的优化排序选项,但 pandas 因为其便利性会额外耗时一点。

默认对单列的排序算法是采用 Numpy 的 quicksort ,当然实际上调用的排序算法是 introsort ,因为堆排序会比较慢。而对于多列的排序算法,Pandas 确保采用的是 Numpy 的 mergesort ,但实际上会采用 Timsort 或者 Radix sort 算法。这两个都是稳定的排序算法,并且对多列进行排序的时候也是必须采用稳定的排序算法。

对于 Pandas,必须记住的是这些关键知识点是:

  • 排序方面的名字:sort_values()
  • 需要指定参数 by=column_name 或者是一个列名字的列表
  • 倒序的关键参数是 ascending
  • 稳定排序是采用 mergesort 参数值

在做数据探索分析的时候,一般在对 DataFrame 做求和和排序数值的时候都采用方法 Series.value_counts()。这里介绍一个代码片段用于对每列出现次数最多的数值进行求和和排序:

for c in df.columns:print(f"---- {c} ----")print(df[c].value_counts().head())

Dask ,是一个基于 Pandas 的用于处理大数据的库,尽管已经开始进行讨论,直到2019年秋天的时候,还没有实现并行排序的功能。关于这个库,其 github 地址:

https://github.com/dask/dask

如果是小数据集,采用 Pandas 进行排序是一个不错的选择,但是数据量很大的时候,想要在 GPU 上并行搜索,就需要采用 TensorFlow 或者 PyTorch 了。

TensorFlow

TensorFlow 是目前最流行的深度学习框架,这里可以看下我写的这篇对比不同深度学习框架的流行性和使用方法的文章:

https://towardsdatascience.com/which-deep-learning-framework-is-growing-fastest-3f77f14aa318?source=friends_link&sk=0a10207f22f4dbc143e7a90a3f843515

下面的介绍都是 TensorFlow 2.0 版本的 GPU 版本。

在 TensorFlow 中,排序方法是 tf.sort(my_tensor) ,返回的是一个排序好的 tensor 的拷贝。可选的参数有:

  • axis :{int, optional},选择在哪个维度进行排序操作。默认是 -1,表示最后一个维度。
  • direction:{ascending or discending}。升序还是降序。
  • name:{str, optional}。给这个操作的命名。

tf.sort 采用的是 top_k 方法,而 top_k 是采用 CUB 库来使得 CUDA GPUs 更容易实现并行化操作。正如官方文档说的:

CUB 提供给 CUDA 编程模型的每一层提供了最好的可复用的软件组件。

TensorFlow 的排序算法通过 CUB 库采用在 GPU 上的 radix sort ,详细介绍可以查看:

https://github.com/tensorflow/tensorflow/issues/288

TensorFlow 的 GPU 信息可以查看:

https://www.tensorflow.org/install/gpu

如果需要让 GPU 兼容 2.0 版本,需要采用下列安装命令:

!pip3 install tensorflow-gpu==2.0.0-beta1

下面这个代码可以查看是否每行代码都在 GPU 或者 CPU 上运行:

tf.debugging.set_log_device_placement(True)

如果需要指定使用一个 GPU, 代码如下所示:

with tf.device('/GPU:0'):%time tf.sort(my_tf_tensor)

如果是想用CPU,只需要将上述代码第一行修为: with tf.device('/CPU:0'),也就是替换 GPU 为 CPU 即可。

tf.sort() 是非常容易记住的方法,另外就是记住需要改变排序顺序,是修改参数 direction

PyTorch

PyTorch 的排序方法是:torch.sort(my_tensor),返回的也是排序好的 tensor 的拷贝,可选参数有:

  • dim :{dim, optional}。排序的维度。
  • descending:{bool, optional}。控制排序的顺序(升序还是降序)
  • out:{tuple, optional}Tensor, LongTensor 的输出元祖,可用于作为输出的缓存。

通过下列代码来指定采用 GPU:

gpu_tensor=my_pytorch_tensor.cuda()
%time torch.sort(gpu_tensor)

PyTorch 在面对一个数据量大于一百万行乘10万列的数据集的时候,是通过 Thrust 实现分割的并行排序。

但不幸的是,我尝试在谷歌的 Cola 上通过 Numpy 构建一个 1.1M * 100 K 的随机数据集的时候出现内存不足的错误,然后尝试用 GCP 的 416 MB,出现同样的内存不足的错误。

Thrust 是一个并行算法库,可以使得性能在 GPUs 和多核 GPUs 之间移植。它可以自动选择最有效率的排序算法实现。而刚刚介绍的 TensorFlow 使用的 CUB 库是对 Thrust 的封装。所以 PyTorch 和 TensorFlow 都采用相似的排序算法实现方式。

和 TensorFlow 一样,PyTorch 的排序方法也是非常直接,很容易记住:torch.sort()。两者稍微不同的就是排序顺序的参数名字:TensorFlow 是 direction,而 PyTorch 是 descending 。另外,不要忘记通过 .cuda() 方法指定采用 GPU 来提高对大数据集的计算速度。

在大数据集通过 GPU 进行排序是很好的选择,但直接在 SQL 上排序也是有意义的。

SQL

在 SQL 中进行排序通常都是非常快速,特别是数据加载到内存中的时候。

SQL 只是一个说明书,并没有指定排序算法的具体实现方式。比如 Postgres 根据环境选择采用 disk merge sort ,或者 quick sort 。如果内存足够,可以让数据加载在内存中,提高排序的速度。通过设置 work_mem 来增加可用的内存,具体查看:

https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server

其他的 SQL 数据库采用不同的排序算法,比如根据下面这个回答,谷歌的 BigQuery 通过一些技巧实现 introsort

https://stackoverflow.com/a/53026600/4590385

在 SQL 中进行排序是通过命令 ORDER_BY ,这个用法和 python 的实现还是有区别的。但它这个命令名字很独特,所以很容易记住。

如果是实现降序,采用关键词 DESC。所以查询顾客的名字,并根据字母表的倒序来返回的语句是如下所示:

SELECT Names FROM Customers
ORDER BY Names DESC;

比较

对上述介绍的方法,我都做了一个分析,采用同样的 100万数据,单列,数组或者列表的数据格式。使用的是谷歌的 Colab Jupyter Notebook,然后硬件方面是 K80 GPU, Intel(R) 的 Xeon(R) CPU @2.30GHZ。

源码地址:https://colab.research.google.com/drive/1NNarscUZHUnQ5v-FjbfJmB5D3kyyq9Av

对比结果如下所示:

8a4254401ba04cd735c1f5f289cd7924.gif

根据上图可知:

  • GPU 版本的 PyTorch 是速度最快的;
  • 对于 numpy 和 pandas,采用 inplace 都比拷贝数据更快;
  • 默认的 pandas 的 quicksort 速度很快
  • 大部分 pandas 的相同排序算法实现都会慢过 numpy
  • TensorFlow 在 CPU 上速度很快,而 TensorFlow-gpu 版本在 CPU 上使用会变慢,在 GPU 上排序更慢,看起来这可能是一个 bug;
  • 原生的 Python inplace 的排序速度非常慢,对比最快的 GPU 版的 PyTorch 要慢接近 100 倍。多次测量这个方法来确保这不是异常情况。

另外,这就是一个小小的测试,绝对不是权威的结果。

总结

最后,通常我们都不需要自己实现排序算法,目前各个库实现的方法以及很强大了。它们也并不是只采用一种排序算法,都是通过对不同类型的数据进行测试不同的排序算法,从而选择不同情况下最佳的排序算法,甚至有的实现会改进算法本身来提高排序的速度。

本文介绍了在不同的 Python 库和 SQL 进行排序的方法,一般来说只需要记得采用哪个参数实现哪个操作,然后下面是我的一些建议:

  • 对比较小的数据集,采用 Pandas 的默认的 sort_values() 进行数据探索分析;
  • 对于大数据集,或者需要优先考虑速度,尝试 numpy 的inplacemergesort ,或者 PyTorch 、TensorFlow 在 GPU 上的并行实现,或者是 SQL。

关于在 GPU 进行排序的做法,可以查看这篇文章:

https://devtalk.nvidia.com/default/topic/951795/fastest-sorting-algorithm-on-gpu-currently/


参考

  1. https://docs.python.org/3/library/stdtypes.html#list.sort
  2. https://docs.python.org/3/library/functions.html#sorted
  3. https://skerritt.blog/timsort-the-fastest-sorting-algorithm-youve-never-heard-of/
  4. https://docs.scipy.org/doc/numpy-1.16.0/reference/generated/numpy.ndarray.sort.html#numpy.ndarray.sort
  5. https://docs.scipy.org/doc/numpy-1.16.0/reference/generated/numpy.sort.html#numpy.sort
  6. https://en.wikipedia.org/wiki/Introsort
  7. https://github.com/numpy/numpy/blob/v1.16.1/numpy/core/fromnumeric.py#L815-L935
  8. https://github.com/dask/dask
  9. https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/sort
  10. https://towardsdatascience.com/which-deep-learning-framework-is-growing-fastest-3f77f14aa318?source=friends_link&sk=0a10207f22f4dbc143e7a90a3f843515
  11. https://nvlabs.github.io/cub/
  12. https://github.com/tensorflow/tensorflow/issues/288
  13. https://thrust.github.io/
  14. https://madusudanan.com/blog/all-you-need-to-know-about-sorting-in-postgres/
  15. https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server
  16. https://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Which sorting algorithm does bigquery ORDER BY clause uses?https://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385dask/daskhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Which sorting algorithm does bigquery ORDER BY clause uses?https://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Which sorting algorithm does bigquery ORDER BY clause uses?https://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385dask/daskhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Which sorting algorithm does bigquery ORDER BY clause uses?https://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385Tuning Your PostgreSQL Serverhttps://stackoverflow.com/a/53026600/4590385Sorting tensors · Issue #288 · tensorflow/tensorflowhttps://stackoverflow.com/a/53026600/4590385



推荐阅读
  • 本文介绍了如何在 Spring 3.0.5 中使用 JdbcTemplate 插入数据并获取 MySQL 表中的自增主键。 ... [详细]
  • 基于iSCSI的SQL Server 2012群集测试(一)SQL群集安装
    一、测试需求介绍与准备公司计划服务器迁移过程计划同时上线SQLServer2012,引入SQLServer2012群集提高高可用性,需要对SQLServ ... [详细]
  • 最详尽的4K技术科普
    什么是4K?4K是一个分辨率的范畴,即40962160的像素分辨率,一般用于专业设备居多,目前家庭用的设备,如 ... [详细]
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • 【图像分类实战】利用DenseNet在PyTorch中实现秃头识别
    本文详细介绍了如何使用DenseNet模型在PyTorch框架下实现秃头识别。首先,文章概述了项目所需的库和全局参数设置。接着,对图像进行预处理并读取数据集。随后,构建并配置DenseNet模型,设置训练和验证流程。最后,通过测试阶段验证模型性能,并提供了完整的代码实现。本文不仅涵盖了技术细节,还提供了实用的操作指南,适合初学者和有经验的研究人员参考。 ... [详细]
  • 通过使用CIFAR-10数据集,本文详细介绍了如何快速掌握Mixup数据增强技术,并展示了该方法在图像分类任务中的显著效果。实验结果表明,Mixup能够有效提高模型的泛化能力和分类精度,为图像识别领域的研究提供了有价值的参考。 ... [详细]
  • 本文深入探讨了数据库性能优化与管理策略,通过实例分析和理论研究,详细阐述了如何有效提升数据库系统的响应速度和处理能力。文章首先介绍了数据库性能优化的基本原则和常用技术,包括索引优化、查询优化和存储管理等。接着,结合实际应用场景,讨论了如何利用容器化技术(如Docker)来部署和管理数据库,以提高系统的可扩展性和稳定性。最后,文章还提供了具体的配置示例和最佳实践,帮助读者在实际工作中更好地应用这些策略。 ... [详细]
  • 图像分割技术在人工智能领域中扮演着关键角色,其中语义分割、实例分割和全景分割是三种主要的方法。本文对这三种分割技术进行了详细的对比分析,探讨了它们在不同应用场景中的优缺点和适用范围,为研究人员和从业者提供了有价值的参考。 ... [详细]
  • 表面缺陷检测数据集综述及GitHub开源项目推荐
    本文综述了表面缺陷检测领域的数据集,并推荐了多个GitHub上的开源项目。通过对现有文献和数据集的系统整理,为研究人员提供了全面的资源参考,有助于推动该领域的发展和技术进步。 ... [详细]
  • 使用虚拟机配置服务器
    本文详细介绍了如何使用虚拟机配置服务器,包括购买云服务器的操作步骤、系统默认配置以及相关注意事项。通过这些步骤,您可以高效地配置和管理您的服务器。 ... [详细]
  • 基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析
    基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析 ... [详细]
  • 在Windows环境下离线安装PyTorch GPU版时,首先需确认系统配置,例如本文作者使用的是Win8、CUDA 8.0和Python 3.6.5。用户应根据自身Python和CUDA版本,在PyTorch官网查找并下载相应的.whl文件。此外,建议检查系统环境变量设置,确保CUDA路径正确配置,以避免安装过程中可能出现的兼容性问题。 ... [详细]
  • 深入解析经典卷积神经网络及其实现代码
    深入解析经典卷积神经网络及其实现代码 ... [详细]
  • 利用PaddleSharp模块在C#中实现图像文字识别功能测试
    PaddleSharp 是 PaddleInferenceCAPI 的 C# 封装库,适用于 Windows (x64)、NVIDIA GPU 和 Linux (Ubuntu 20.04) 等平台。本文详细介绍了如何使用 PaddleSharp 在 C# 环境中实现图像文字识别功能,并进行了全面的功能测试,验证了其在多种硬件配置下的稳定性和准确性。 ... [详细]
  • NVIDIA最新推出的Ampere架构标志着显卡技术的一次重大突破,不仅在性能上实现了显著提升,还在能效比方面进行了深度优化。该架构融合了创新设计与技术改进,为用户带来更加流畅的图形处理体验,同时降低了功耗,提升了计算效率。 ... [详细]
author-avatar
等号拖轮_496
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有