用Python中的字典来处理索引统计的方法

作者:xrzs 时间:2022-05-28 19:43:45 

最近折腾索引引擎以及数据统计方面的工作比较多, 与 Python 字典频繁打交道, 至此整理一份此方面 API 的用法与坑法备案.

    索引引擎的基本工作原理便是倒排索引, 即将一个文档所包含的文字反过来映射至文档; 这方面算法并没有太多花样可言, 为了增加效率, 索引数据尽可往内存里面搬, 此法可效王献之习书法之势, 只要把十八台机器内存全部塞满, 那么基本也就功成名就了. 而基本思路举个简单例子, 现在有以下文档 (分词已经完成) 以及其包含的关键词


 doc_a: [word_w, word_x, word_y]
 doc_b: [word_x, word_z]
 doc_c: [word_y]

将其变换为


 word_w -> [doc_a]
 word_x -> [doc_a, doc_b]
 word_y -> [doc_a, doc_c]
 word_z -> [doc_b]

    写成 Python 代码, 便是
 


doc_a = {'id': 'a', 'words': ['word_w', 'word_x', 'word_y']}
doc_b = {'id': 'b', 'words': ['word_x', 'word_z']}
doc_c = {'id': 'c', 'words': ['word_y']}

docs = [doc_a, doc_b, doc_c]
indices = dict()

for doc in docs:
 for word in doc['words']:
   if word not in indices:
     indices[word] = []
   indices[word].append(doc['id'])

print indices

    不过这里有个小技巧, 就是对于判断当前词是否已经在索引字典里的分支
 


if word not in indices:
 indices[word] = []

可以被  dict  的  setdefault(key, default=None)  接口替换. 此接口的作用是, 如果  key  在字典里, 那么好说, 拿出对应的值来; 否则, 新建此  key , 且设置默认对应值为  default . 但从设计上来说, 我不明白为何  default  有个默认值  None , 看起来并无多大意义, 如果确要使用此接口, 大体都会自带默认值吧, 如下
 


for doc in docs:
 for word in doc['words']:
   indices. setdefault(word, []) .append(doc['id'])

    这样就省掉分支了, 代码看起来少很多.
    不过在某些情况下,  setdefault  用起来并不顺手: 当  default  值构造很复杂时, 或产生  default  值有副作用时, 以及一个之后会说到的情况; 前两种情况一言以蔽之, 就是  setdefault  不适用于  default  需要惰性求值的场景. 换言之, 为了兼顾这种需求,  setdefault  可能会设计成
 


def setdefault(self, key, default_factory):
 if key not in self:
   self[key] = default_factory()
 return self[key]

倘若真如此, 那么上面的代码应改成
 


for doc in docs:
 for word in doc['words']:
   indices.setdefault(word, list ).append(doc['id'])

不过实际上有其它替代方案, 这个最后会提到.

    如果说上面只是一个能预见但实际上可能根本不会遇到的 API 缺陷, 那么下面这个就略打脸了.
    考虑现在要进行词频统计, 即一个词在文章中出现了多少次, 如果直接拿  dict  来写, 大致是
 


def word_count(words):
 count = dict()
 for word in words:
   count.setdefault(word, 0) += 1
 return count

print word_count(['hiiragi', 'kagami', 'hiiragi', 'tukasa', 'yosimizu', 'kagami'])

    当你兴致勃勃地跑起上面代码时, 代码会以迅雷不及掩脸之势把异常甩到你鼻尖上 --- 因为出现在  +=  操作符左边的  count.setdefault(word, 0)  在 Python 中不是一个左值. 怎样, 现在开始念叨 C艹 类型体系的好了吧.

    因为 Python 把默认的字面常量  {}  等价于  dict()  就认为  dict  是银弹的思想是要不得的; Python 里面各种数据结构不少, 解决统计问题, 理想的方案是  collections.defaultdict  这个类. 下面的代码想必看一眼就明白
 


from collections import defaultdict

doc_a = {'id': 'a', 'words': ['word_w', 'word_x', 'word_y']}
doc_b = {'id': 'b', 'words': ['word_x', 'word_z']}
doc_c = {'id': 'c', 'words': ['word_y']}

docs = [doc_a, doc_b, doc_c]
indices = defaultdict(list)

for doc in docs:
 for word in doc['words']:
   indices[word].append(doc['id'])

print indices

def word_count(words):
 count = defaultdict(int)
 for word in words:
   count[word] += 1
 return count

print word_count(['hiiragi', 'kagami', 'hiiragi', 'tukasa', 'yosimizu', 'kagami'])

    完满解决了之前遇到的那些破事.

    此外  collections  里还有个  Counter , 可以粗略认为它是  defaultdict(int)  的扩展.

标签:Python
0
投稿

猜你喜欢

  • python实现Adapter模式实例代码

    2021-10-20 00:43:02
  • pygame实现俄罗斯方块游戏(AI篇2)

    2022-03-02 13:03:10
  • Python利用pyHook实现监听用户鼠标与键盘事件

    2021-09-04 19:59:59
  • Python基础之getpass模块详细介绍

    2021-03-06 13:47:13
  • 使用Python做定时任务及时了解互联网动态

    2021-07-08 17:54:16
  • 如何用python获取到照片拍摄时的详细位置(附源码)

    2023-04-22 05:04:18
  • 3 个超有用的 Python 编程小技巧

    2022-12-02 20:32:03
  • MySQL主从复制的原理及配置方法(比较详细)

    2024-01-28 18:21:02
  • Go实现双向链表的示例代码

    2024-03-13 04:11:45
  • 浅谈ASP自动采集程序及入库

    2007-08-17 11:25:00
  • 解析:Perl下应当如何连接Access数据库

    2008-11-28 16:40:00
  • asp网上考试设计思路是怎样的?

    2010-07-14 21:09:00
  • 解决Python中由于logging模块误用导致的内存泄露

    2021-08-24 08:04:46
  • Mysql中的事务是什么如何使用

    2024-01-21 18:42:26
  • 详解vue-router和vue-cli以及组件之间的传值

    2024-05-21 10:31:10
  • MySQL Index Condition Pushdown(ICP)性能优化方法实例

    2024-01-19 20:08:25
  • python递归函数求n的阶乘,优缺点及递归次数设置方式

    2022-12-08 16:17:08
  • Django 实现前端图片压缩功能的方法

    2022-11-05 09:05:16
  • 用ASP和SQL语句动态的创建Access表

    2008-10-14 16:59:00
  • Python 使用PIL numpy 实现拼接图片的示例

    2021-03-20 02:50:20
  • asp之家 网络编程 m.aspxhome.com