【问题标题】:List with many dictionaries VS dictionary with few lists?有很多字典的列表 VS 有很少列表的字典?
【发布时间】:2015-08-11 22:20:16
【问题描述】:

我正在用这样的数据集做一些练习:

包含许多词典的列表

users = [
    {"id": 0, "name": "Ashley"},
    {"id": 1, "name": "Ben"},
    {"id": 2, "name": "Conrad"},
    {"id": 3, "name": "Doug"},
    {"id": 4, "name": "Evin"},
    {"id": 5, "name": "Florian"},
    {"id": 6, "name": "Gerald"}
]

列表很少的字典

users2 = {
    "id": [0, 1, 2, 3, 4, 5, 6],
    "name": ["Ashley", "Ben", "Conrad", "Doug","Evin", "Florian", "Gerald"]
}

Pandas 数据框

import pandas as pd
pd_users = pd.DataFrame(users)
pd_users2 = pd.DataFrame(users2)
print pd_users == pd_users2

问题:

  1. 我应该像 users 还是像 users2 那样构建数据集?
  2. 是否存在性能差异?
  3. 一个比另一个更易读吗?
  4. 是否有我应该遵循的标准?
  5. 我通常将这些转换为 pandas 数据帧。当我这样做时,两个版本是相同的......对吗?
  6. 每个元素的输出都是正确的,所以我是否使用 panda df 并不重要?

【问题讨论】:

  • 很好的问题我会选择第一个选项,因为与第二个选项相比,我进行搜索和插入操作会不那么乏味
  • 我会选择第一个,只要使用方便是最重要的方面。移动物品时,将 ID 与 NAME 放在一起会很方便。
  • 第一个版本很容易排序,而第二个版本不行。

标签: python pandas dataset


【解决方案1】:

这与 column oriented databases 与面向行有关。您的第一个示例是面向行的数据结构,第二个示例是面向列的。在 Python 的特定情况下,使用slots 可以使第一个更高效,这样就不需要为每一行复制列字典。

哪种形式效果更好在很大程度上取决于您如何处理数据;例如,如果您只访问任何行的所有内容,那么面向行是很自然的。同时,当您按特定字段搜索时,面向列可以更好地利用缓存等(在 Python 中,这可能会因大量使用引用而减少;array 之类的类型可以对此进行优化)。传统的面向行的数据库经常使用面向列的排序索引来加快查找速度,了解这些技术后,您可以使用键值存储实现任意组合。

Pandas 确实将您的两个示例转换为相同的格式,但是对于面向行的结构而言,转换本身的成本更高,因为必须读取每个单独的字典。所有这些成本都可能是微不足道的。

在您的示例中还有第三个选项不明显:在这种情况下,您只有两列,其中一列是从 0 开始的连续范围内的整数 ID。这可以按条目本身的顺序存储,这意味着整个结构将在您称为users2['name'] 的列表中找到;但值得注意的是,没有位置的条目是不完整的。该列表使用 enumerate() 转换为行。数据库通常也有这种特殊情况(例如,sqlite rowid)。

一般来说,从保持代码合理的数据结构开始,并仅在您了解自己的用例并存在可衡量的性能问题时进行优化。 Pandas 之类的工具可能意味着大多数项目无需微调即可正常运行。

【讨论】:

【解决方案2】:

查找的时间复杂度 -

  • 列表 - O(n)
  • 字典 - O(1)

但是,如果您的数据不是那么大,而且现代处理器也非常高效,那也不会造成太大影响。
您应该使用查找在语法上更清晰和可读(可读性很重要)的那个。
第一个选项非常合适,因为变量是用户的集合(已分配一个 id),而第二个选项只是用户名和 id 的集合。

【讨论】:

  • “您应该使用查找在语法上更清晰和可读的那个”+1。但我认为时间复杂度并不重要,因为我们不知道他是如何访问这些数据的。
  • 实际上,Python 的列表是引用数组,并且有 O(1) 查找。您可能一直在期待链接列表。
  • @YannVernier 他的意思是在列表中查找特定值,而不仅仅是按索引访问。
  • dict 在查找值方面并不比list 好;与association lists 相比,仅在查找键时才重要。由于dict 在Python 中总是可用的,我们很少使用这种形式,但是当creating a dict 时它被接受为输入。如果您总是通过同一个键查找并且该键不是从 0 开始的连续整数系列,请使用 dict,而 id 恰好在本例中。
【解决方案3】:

用户

  1. 当您需要附加一些新用户时,只需将所有用户详细信息创建一个新的dict 并附加它

  2. 按照@StevenRumbalski 的建议轻松排序

  3. 搜索会很容易

  4. 随着记录的增长,这更加紧凑且易于管理(对于一些非常多的记录,我认为我们也需要比用户更好的东西)

用户2

  1. 我个人是第一次看到这种情况,如果我有大量记录,我不会处理这种情况。

PS:但我想了解users2 相对于users 的优势 又是一个好问题

【讨论】:

    【解决方案4】:

    一般意义上的users实际上是user元素的集合。所以最好将user 元素定义为一个独立的实体。所以你的第一个选择是正确的。

    【讨论】:

      【解决方案5】:

      关于熊猫方面的一些答案:

      1. 两个数据帧确实是相同的,并且是面向列的,这很好,因为当每列中的数据是同质的(即数字可以存储为整数和浮点数)时,pandas 的效果最好。首先使用 pandas 的一个关键原因是,您可以执行比纯 python 快几个数量级的矢量化数值运算 - 但当数据是异构类型时,这依赖于列式组织。
      2. 如果您愿意,您可以使用pd_users.T 进行转置,然后会看到(通过info()dtypes)所有内容都被存储为通用对象,因为该列同时包含字符串和数字。
      3. 转换后,您可以执行pd_users.set_index('id'),这样您的数据框本质上就是一个以id 为键的字典。反之亦然,name
      4. 在使用 pandas 时,更改索引、然后将它们改回、转置、子集等是很常见的(并且通常很快),因此通常不需要在开始时过多考虑结构。只需随时更改即可。
      5. 这可能是一个切线,但您上面所拥有的更简单的 pandas 模拟可能是 Series 而不是 DataFrame。系列本质上是数据框的一列,尽管它实际上只是一个带有索引(“键”)的一维数据数组。

      快速演示(使用df作为数据框名称,通用约定):

      >>> df.set_index('name')
      
               id
      name       
      Ashley    0
      Ben       1
      Conrad    2
      Doug      3
      Evin      4
      Florian   5
      Gerald    6
      
      >>> df.set_index('name').T
      
      name  Ashley  Ben  Conrad  Doug  Evin  Florian  Gerald
      id         0    1       2     3     4        5       6
      
      >>> df.set_index('name').loc['Doug']
      
      id    3
      Name: Doug, dtype: int64
      

      【讨论】:

      • 嘿!您提到两个数据框都是面向列的。现在最受好评的答案建议一个是列,另一个是行。你能确认一下吗?
      • 我相信@YannVernier 只是指之前转换为熊猫的情况。您已经用pd_users == pd_users2 证明了它们与您自己是一样的。但是你可以做pd_users == pd_users2.T(在其中一个上放一个转置)来进一步验证。它将引发异常,因为这两个数据帧不再符合。除了检查相等性之外,仅打印数据框即可显示 pandas 如何根据行和列来构造数据。
      • 嗯,有道理。感谢您的澄清。
      【解决方案6】:

      字典列表的第一个选项会更好,原因很少。 List 确实提供了诸如 EXTEND、APPENT、PUSH 之类的方法,这些方法在字典中是不可用的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-21
        • 2023-03-28
        • 2018-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多