包含很多字典的列表 VS 包含很少列表的字典?
List with many dictionaries VS dictionary with few lists?
我正在用这样的数据集做一些练习:
包含许多词典的列表
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
问题:
- 我应该像 users 还是像 users2 那样构建数据集?
- 是否存在性能差异?
- 一个比另一个更易读吗?
- 有没有我应该遵循的标准?
- 我通常将它们转换为 pandas 数据帧。当我这样做时,两个版本是相同的……对吗?
- 每个元素的输出都是真实的,所以我是否使用 panda df 并不重要?
一般意义上的users
其实就是user
个元素的集合。所以最好将 user
元素定义为一个独立的实体。所以你的第一个选择是正确的。
查找的时间复杂度 -
- 列表 - O(n)
- 字典 - O(1)
但是,如果您的数据不是那么大,而且现代处理器非常高效,那也没什么大不了的。
您应该选择查找在语法上更清晰和可读(可读性很重要)的那个。
第一个选项非常合适,因为变量是用户的集合(已分配了一个 ID),而第二个选项只是用户名和 ID 的集合。
用户
当您需要添加一些新用户时,只需为所有用户详细信息创建一个新的 dict
并添加它
按照@StevenRumbalski 的建议轻松排序
搜索会很容易
随着记录的增长,这更加紧凑且易于管理(对于一些非常多的记录,我认为我们也需要比用户更好的东西)
用户 2
- 我个人是第一次看到这个,如果我有大量记录,我不会处理这个。
PS:但我想了解 users2
相对于 users
的优势
又是一个好问题
这与 column oriented databases versus row oriented. Your first example is a row oriented data structure, and the second is column oriented. In the particular case of Python, the first could be made notably more efficient using slots 相关,因此不需要为每一行复制列字典。
哪种形式效果更好很大程度上取决于您对数据的处理方式;例如,如果您只访问任何行的所有内容,那么面向行是很自然的。同时,面向列可以更好地利用缓存,例如当您通过特定字段进行搜索时(在 Python 中,这可能会因引用的大量使用而减少;像 array 这样的类型可以优化它) .传统的面向行的数据库经常使用面向列的排序索引来加快查找速度,了解这些技术后,您可以使用键值存储实现任何组合。
Pandas 确实将您的两个示例都转换为相同的格式,但是转换本身对于面向行的结构来说成本更高,因为必须读取每个单独的字典。所有这些成本可能都是微不足道的。
第三个选项在您的示例中不明显:在这种情况下,您只有两列,其中一列是从 0 开始的连续范围内的整数 ID。这可以按条目本身的顺序存储,这意味着整个结构将在您称为 users2['name']
的列表中找到;但值得注意的是,没有他们的位置,这些条目是不完整的。该列表使用 enumerate() 转换为行。数据库通常也有这种特殊情况(例如,sqlite rowid)。
一般来说,从让您的代码保持合理的数据结构开始,并且仅当您了解您的用例并且存在可衡量的性能问题时才进行优化。 Pandas 之类的工具可能意味着大多数项目无需微调即可正常运行。
字典列表的第一个选项会好得多,原因不多。 List 确实提供了诸如 EXTEND、APPENT、PUSH 之类的方法,这些方法在字典中是不容易获得的。
关于pandas方面的一些回答:
- 两个数据帧确实相同并且都是面向列的,这很好,因为 pandas 在每列中的数据是同类数据时效果最好(即数字可以存储为整数和浮点数)。首先使用 pandas 的一个关键原因是您可以执行比纯 python 快几个数量级的矢量化数值运算——但是当数据是异构类型时,这依赖于列式组织。
- 如果你愿意,你可以做
pd_users.T
转置,然后会看到(通过 info()
或 dtypes
)所有内容都存储为通用对象,因为该列同时包含字符串和数字。
- 转换后,您可以执行
pd_users.set_index('id')
,这样您的数据框本质上就是一个以 id
作为键的字典。反之亦然 name
.
- 在使用 pandas 时,更改索引然后将它们改回、转置、子集等是很常见的(而且通常很快),因此通常不需要过多考虑结构开始。只需根据需要即时更改即可。
- 这可能有点离题了,但是更简单的 pandas 类似上面的内容可能是
Series
而不是 DataFrame
。系列本质上是数据框的一列,尽管它实际上只是一个带有索引 ("keys") 的一维数据数组。
快速演示(使用 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
我正在用这样的数据集做一些练习:
包含许多词典的列表
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
问题:
- 我应该像 users 还是像 users2 那样构建数据集?
- 是否存在性能差异?
- 一个比另一个更易读吗?
- 有没有我应该遵循的标准?
- 我通常将它们转换为 pandas 数据帧。当我这样做时,两个版本是相同的……对吗?
- 每个元素的输出都是真实的,所以我是否使用 panda df 并不重要?
users
其实就是user
个元素的集合。所以最好将 user
元素定义为一个独立的实体。所以你的第一个选择是正确的。
查找的时间复杂度 -
- 列表 - O(n)
- 字典 - O(1)
但是,如果您的数据不是那么大,而且现代处理器非常高效,那也没什么大不了的。
您应该选择查找在语法上更清晰和可读(可读性很重要)的那个。
第一个选项非常合适,因为变量是用户的集合(已分配了一个 ID),而第二个选项只是用户名和 ID 的集合。
用户
当您需要添加一些新用户时,只需为所有用户详细信息创建一个新的
dict
并添加它按照@StevenRumbalski 的建议轻松排序
搜索会很容易
随着记录的增长,这更加紧凑且易于管理(对于一些非常多的记录,我认为我们也需要比用户更好的东西)
用户 2
- 我个人是第一次看到这个,如果我有大量记录,我不会处理这个。
PS:但我想了解 users2
相对于 users
的优势
又是一个好问题
这与 column oriented databases versus row oriented. Your first example is a row oriented data structure, and the second is column oriented. In the particular case of Python, the first could be made notably more efficient using slots 相关,因此不需要为每一行复制列字典。
哪种形式效果更好很大程度上取决于您对数据的处理方式;例如,如果您只访问任何行的所有内容,那么面向行是很自然的。同时,面向列可以更好地利用缓存,例如当您通过特定字段进行搜索时(在 Python 中,这可能会因引用的大量使用而减少;像 array 这样的类型可以优化它) .传统的面向行的数据库经常使用面向列的排序索引来加快查找速度,了解这些技术后,您可以使用键值存储实现任何组合。
Pandas 确实将您的两个示例都转换为相同的格式,但是转换本身对于面向行的结构来说成本更高,因为必须读取每个单独的字典。所有这些成本可能都是微不足道的。
第三个选项在您的示例中不明显:在这种情况下,您只有两列,其中一列是从 0 开始的连续范围内的整数 ID。这可以按条目本身的顺序存储,这意味着整个结构将在您称为 users2['name']
的列表中找到;但值得注意的是,没有他们的位置,这些条目是不完整的。该列表使用 enumerate() 转换为行。数据库通常也有这种特殊情况(例如,sqlite rowid)。
一般来说,从让您的代码保持合理的数据结构开始,并且仅当您了解您的用例并且存在可衡量的性能问题时才进行优化。 Pandas 之类的工具可能意味着大多数项目无需微调即可正常运行。
字典列表的第一个选项会好得多,原因不多。 List 确实提供了诸如 EXTEND、APPENT、PUSH 之类的方法,这些方法在字典中是不容易获得的。
关于pandas方面的一些回答:
- 两个数据帧确实相同并且都是面向列的,这很好,因为 pandas 在每列中的数据是同类数据时效果最好(即数字可以存储为整数和浮点数)。首先使用 pandas 的一个关键原因是您可以执行比纯 python 快几个数量级的矢量化数值运算——但是当数据是异构类型时,这依赖于列式组织。
- 如果你愿意,你可以做
pd_users.T
转置,然后会看到(通过info()
或dtypes
)所有内容都存储为通用对象,因为该列同时包含字符串和数字。 - 转换后,您可以执行
pd_users.set_index('id')
,这样您的数据框本质上就是一个以id
作为键的字典。反之亦然name
. - 在使用 pandas 时,更改索引然后将它们改回、转置、子集等是很常见的(而且通常很快),因此通常不需要过多考虑结构开始。只需根据需要即时更改即可。
- 这可能有点离题了,但是更简单的 pandas 类似上面的内容可能是
Series
而不是DataFrame
。系列本质上是数据框的一列,尽管它实际上只是一个带有索引 ("keys") 的一维数据数组。
快速演示(使用 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