Python3 CookBook | 数据结构和算法(二)

简介: 工作中有时会遇到这样的需求,取出数据中前面 10% 的值,或者最后 10% 的值。我们可以先对这个列表进行排序,然后再进行切片操作,很轻松的解决这个问题。但是,有没有更好的方法呢?

1、查找最大或最小的 N 个元素


工作中有时会遇到这样的需求,取出数据中前面 10% 的值,或者最后 10% 的值。

我们可以先对这个列表进行排序,然后再进行切片操作,很轻松的解决这个问题。但是,有没有更好的方法呢?

heapq 模块有两个函数 nlargest() 和 nsmallest() 可以完美解决这个问题。


In [50]: import heapq
In [51]: n = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2, 23, 45, 76]
In [52]: heapq.nlargest(3, n)
Out[52]: [76, 45, 42]
In [53]: heapq.nsmallest(3, n)
Out[53]: [-4, 1, 2]
复制代码


如果是取排在前面的 10% 应该怎么做?


heapq.nlargest(round(len(n)/10), n)
复制代码


而且,使用这两个函数还会有更好的性能,因为在底层实现里面,会先把数据进行堆排序后放入一个列表中,然后再进行后续操作。大家如果对堆数据结构感兴趣的话,可以继续进行深入研究,由于我了解的并不深,也没办法再展开了。

但是也并不是什么时候都是这两个函数效果更好,比如只取一个最大值或者最小值,那还是 min() 或 max() 效果更好;如果要查找的元素个数已经跟集合元素个数接近时,那还是用 sorted(items)[:N] 更好,具体情况具体分析吧。


2、序列中出现次数最多的元素


以前碰到这类问题时,我都会手动创建一个字典,然后以列表中元素作为 key,进而统计出 key 出现的次数,再进行比较得到出现次数最多的元素。

殊不知 collections 中就有专门为这类问题设计的类 Counter,瞬间感觉自己蠢爆了,话不多说,直接上代码。


In [54]: from collections import Counter
In [55]: w = ['a', 'b', 'c', 'd', 'a', 'a', 'b']
In [56]: w_count = Counter(w)
In [57]: w_count
Out[57]: Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})
In [58]: w_count['a']
Out[58]: 3
In [59]: top = w_count.most_common(2)
In [60]: top
Out[60]: [('a', 3), ('b', 2)]
复制代码


可以看到,Counter 返回的就是一个字典,想知道哪个元素出现几次,直接取,是不是很方便?

而且还有 most_common 函数,简直不要太棒。


3、过滤序列元素


有一个列表,如下:


In [61]: a = [1, 2, 3, 4, 5, -3]
复制代码


要求过滤所有负数。需要新建一个列表?直接一行代码搞定。


In [64]: [n for n in a if n > 0]
Out[64]: [1, 2, 3, 4, 5]
复制代码


如果要把负数替换成 0 呢?


In [67]: [n if n > 0 else 0 for n in a]
Out[67]: [1, 2, 3, 4, 5, 0]
复制代码


但是有时候过滤条件可能比较复杂,这时就需要借助于 filter() 函数了。


values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):
  try:
    x = int(val)
      return True
  except ValueError:
    return False
ivals = list(filter(is_int, values))
print(ivals)
# Outputs ['1', '2', '-3', '4', '5']
复制代码


4、通过某个关键字将记录分组


有下面这个字典:


rows = [
  {'address': '5412 N CLARK', 'date': '07/01/2012'},
  {'address': '5148 N CLARK', 'date': '07/04/2012'},
  {'address': '5800 E 58TH', 'date': '07/02/2012'},
  {'address': '2122 N CLARK', 'date': '07/03/2012'},
  {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
  {'address': '1060 W ADDISON', 'date': '07/02/2012'},
  {'address': '4801 N BROADWAY', 'date': '07/01/2012'},
  {'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
]
复制代码


那么怎么对这个字典按照 date 进行分组呢?借助于 itertools.groupby() 函数可以解决这个问题,代码如下:


# Sort by the desired field first
rows.sort(key=itemgetter('date'))
# Iterate in groups
for date, items in groupby(rows, key=itemgetter('date')):
  print(date)
  for i in items:
    print(' ', i)
复制代码


输出结果如下:


07/01/2012
  {'address': '5412 N CLARK', 'date': '07/01/2012'}
  {'address': '4801 N BROADWAY', 'date': '07/01/2012'}
07/02/2012
  {'address': '5800 E 58TH', 'date': '07/02/2012'}
  {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}
  {'address': '1060 W ADDISON', 'date': '07/02/2012'}
07/03/2012
  {'address': '2122 N CLARK', 'date': '07/03/2012'}
07/04/2012
  {'address': '5148 N CLARK', 'date': '07/04/2012'}
  {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}
复制代码


需要注意的是,groupby() 函数仅仅检查连续相同的元素,所以在分组之前,一定要先对数据,按照分组字段进行排序。如果没有排序,便得不到想要的结果。


5、映射名称到序列元素


我常常有这样的苦恼,就是有一个列表,然后通过下标来取值,取值时很认真的数所需要元素在第几个,很怕取错值。取到值后开始下面的运算。

一段时间之后,再看这段代码,感觉很陌生,已经忘了带下标的值是什么了,还需要重新看一下这个列表的由来,才找到回忆。

如果能有一个名称映射到元素上就好了,直接通过名称就可以知道元素的含义。collections.namedtuple() 函数就可以解决这个问题。


In [76]: from collections import namedtuple
In [77]: subscriber = namedtuple('Subscriber', ['addr', 'joined'])
In [78]: sub = subscriber('jonesy@example.com', '2012-10-19')
In [79]: sub
Out[79]: Subscriber(addr='jonesy@example.com', joined='2012-10-19')
In [80]: sub.addr
Out[80]: 'jonesy@example.com'
In [81]: sub.joined
Out[81]: '2012-10-19'
复制代码


这样就可以通过名称来取值了,代码可读性也更高。

需要注意的是,这种命名元祖的方式不能直接修改其中的值,直接修改会报错


In [82]: a = namedtuple('SSS', ['name', 'shares', 'price'])
In [83]: _a = a('yongxinz', 1, 2)
In [84]: _a.shares = 4
-----------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-84-f62a5288a29a> in <module>()
> 1 _a.shares = 4
AttributeError: can't set attribute
复制代码


想要修改的话可以使用 _replace() 函数。


In [85]: _a._replace(shares=4)
Out[85]: SSS(name='yongxinz', shares=4, price=2)
复制代码


但是还有一个疑问,如果这个列表元素比较多的话,那就需要定义很多的名称,也比较麻烦,还有更好的方式吗?

未完待续。。。


目录
相关文章
|
2月前
|
机器学习/深度学习 新能源 调度
电力系统短期负荷预测(Python代码+数据+详细文章讲解)
电力系统短期负荷预测(Python代码+数据+详细文章讲解)
187 1
|
2月前
|
缓存 API 网络架构
淘宝item_search_similar - 搜索相似的商品API接口,用python返回数据
淘宝联盟开放平台中,可通过“物料优选接口”(taobao.tbk.dg.optimus.material)实现“搜索相似商品”功能。该接口支持根据商品 ID 获取相似推荐商品,并返回商品信息、价格、优惠等数据,适用于商品推荐、比价等场景。本文提供基于 Python 的实现示例,包含接口调用、数据解析及结果展示。使用时需配置淘宝联盟的 appkey、appsecret 和 adzone_id,并注意接口调用频率限制和使用规范。
|
29天前
|
存储 监控 API
Python实战:跨平台电商数据聚合系统的技术实现
本文介绍如何通过标准化API调用协议,实现淘宝、京东、拼多多等电商平台的商品数据自动化采集、清洗与存储。内容涵盖技术架构设计、Python代码示例及高阶应用(如价格监控系统),提供可直接落地的技术方案,帮助开发者解决多平台数据同步难题。
|
1月前
|
存储 JSON 算法
Python集合:高效处理无序唯一数据的利器
Python集合是一种高效的数据结构,具备自动去重、快速成员检测和无序性等特点,适用于数据去重、集合运算和性能优化等场景。本文通过实例详解其用法与技巧。
87 0
|
3月前
|
存储 Web App开发 前端开发
Python + Requests库爬取动态Ajax分页数据
Python + Requests库爬取动态Ajax分页数据
|
3月前
|
JSON API 数据格式
Python采集京东商品评论API接口示例,json数据返回
下面是一个使用Python采集京东商品评论的完整示例,包括API请求、JSON数据解析
|
14天前
|
JSON API 数据安全/隐私保护
Python采集淘宝评论API接口及JSON数据返回全流程指南
Python采集淘宝评论API接口及JSON数据返回全流程指南
|
16天前
|
数据采集 数据可视化 关系型数据库
基于python大数据的电影数据可视化分析系统
电影分析与可视化平台顺应电影产业数字化趋势,整合大数据处理、人工智能与Web技术,实现电影数据的采集、分析与可视化展示。平台支持票房、评分、观众行为等多维度分析,助力行业洞察与决策,同时提供互动界面,增强观众对电影文化的理解。技术上依托Python、MySQL、Flask、HTML等构建,融合数据采集与AI分析,提升电影行业的数据应用能力。
|
2月前
|
JSON 安全 API
Python处理JSON数据的最佳实践:从基础到进阶的实用指南
JSON作为数据交换通用格式,广泛应用于Web开发与API交互。本文详解Python处理JSON的10个关键实践,涵盖序列化、复杂结构处理、性能优化与安全编程,助开发者高效应对各类JSON数据挑战。
140 1
|
25天前
|
数据可视化 大数据 数据挖掘
基于python大数据的招聘数据可视化分析系统
本系统基于Python开发,整合多渠道招聘数据,利用数据分析与可视化技术,助力企业高效决策。核心功能包括数据采集、智能分析、可视化展示及权限管理,提升招聘效率与人才管理水平,推动人力资源管理数字化转型。

推荐镜像

更多