使用熊猫的“大数据”工作流程


979

在学习熊猫的过程中,我试图迷惑了这个问题很多月。我在日常工作中使用SAS,这非常有用,因为它提供了核心支持。但是,由于许多其他原因,SAS作为一个软件也是很糟糕的。

有一天,我希望用python和pandas取代我对SAS的使用,但是我目前缺少大型数据集的核心工作流程。我不是在谈论需要分布式网络的“大数据”,而是文件太大而无法容纳在内存中,但文件又足够小而无法容纳在硬盘上。

我的第一个想法是用来HDFStore将大型数据集保存在磁盘上,然后仅将需要的部分拉入数据帧中进行分析。其他人提到MongoDB是更易于使用的替代方案。我的问题是这样的:

什么是实现以下目标的最佳实践工作流:

  1. 将平面文件加载到永久的磁盘数据库结构中
  2. 查询该数据库以检索要输入到熊猫数据结构中的数据
  3. 处理熊猫中的片段后更新数据库

现实世界中的示例将不胜感激,尤其是那些从“大数据”中使用熊猫的人。

编辑-我希望如何工作的示例:

  1. 迭代地导入一个大的平面文件,并将其存储在永久的磁盘数据库结构中。这些文件通常太大而无法容纳在内存中。
  2. 为了使用Pandas,我想读取这些数据的子集(通常一次只读取几列),使其适合内存。
  3. 我将通过对所选列执行各种操作来创建新列。
  4. 然后,我将不得不将这些新列添加到数据库结构中。

我正在尝试找到执行这些步骤的最佳实践方法。阅读有关熊猫和pytables的链接,似乎添加一个新列可能是个问题。

编辑-专门回答杰夫的问题:

  1. 我正在建立消费者信用风险模型。数据类型包括电话,SSN和地址特征;财产价值;犯罪记录,破产等贬义信息。我每天使用的数据集平均有近1,000到2,000个字段,这些字段是混合数据类型:数字和字符数据的连续,名义和有序变量。我很少追加行,但是我确实执行许多创建新列的操作。
  2. 典型的操作涉及使用条件逻辑将几个列合并到一个新的复合列中。例如,if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'。这些操作的结果是数据集中每个记录的新列。
  3. 最后,我想将这些新列添加到磁盘数据结构中。我将重复步骤2,使用交叉表和描述性统计数据探索数据,以寻找有趣的直观关系进行建模。
  4. 一个典型的项目文件通常约为1GB。文件组织成这样的方式,其中一行包含消费者数据记录。每条记录的每一行都有相同的列数。情况总是如此。
  5. 创建新列时,我会按行进行子集化是非常罕见的。但是,在创建报告或生成描述性统计信息时,对行进行子集化是很常见的。例如,我可能想为特定业务创建一个简单的频率,例如零售信用卡。为此,除了我要报告的任何列之外,我将只选择那些业务线=零售的记录。但是,在创建新列时,我将拉出所有数据行,而仅提取操作所需的列。
  6. 建模过程要求我分析每一列,寻找与某些结果变量有关的有趣关系,并创建描述这些关系的新复合列。我探索的列通常以小集合形式完成。例如,我将集中讨论一组20个仅涉及属性值的列,并观察它们与贷款违约的关系。一旦探索了这些列并创建了新的列,我便转到另一组列,例如大学学历,并重复该过程。我正在做的是创建候选变量,这些变量解释我的数据和某些结果之间的关系。在此过程的最后,我应用了一些学习技术,这些技术可以根据这些复合列创建方程。

我很少向数据集添加行。我几乎总是会创建新列(统计/机器学习术语中的变量或功能)。


1
核心尺寸/完整尺寸的比率是1%,10%吗?有关系吗-如果您可以将cols压缩为int8或过滤掉嘈杂的行,这是否会使您的计算思想循环从数小时变为数分钟?(还添加标签大数据。)
denis

1
存储float32而不是float64,并在可能的情况下存储int8 应该是微不足道的(尽管不知道内部会使用什么工具/函数进行float64)
denis

您可以将您的任务分解成很多工作吗?
Andrew Scott Evans

1
一个不错的2019解决方案,做大熊猫像“中的”数据不适合在内存操作是DASK
lunguini

在刚开始时,您可能需要考虑使用python + pandas的替代方法。考虑以下事实:Python是通用编程语言(不是用于数据处理和分析的DSL),而pandas是最重要的库。我会考虑看R或kdb。
亨利·亨林森

Answers:


621

我通常以这种方式使用数十GB的数据,例如,我在磁盘上有一些表,这些表是通过查询读取,创建数据并追加回去的。

值得阅读文档以及该线程的后期内容,以获取有关如何存储数据的一些建议。

将影响您存储数据方式的详细信息,例如:
尽可能多地提供详细信息;我可以帮助您建立结构。

  1. 数据大小,行数,列数,列类型;您要追加行还是仅追加列?
  2. 典型的操作将是什么样的。例如,对列进行查询以选择一堆行和特定的列,然后执行一个操作(在内存中),创建新列并保存。
    (提供一个玩具示例可以使我们提供更具体的建议。)
  3. 处理完之后,您该怎么办?步骤2是临时的还是可重复的?
  4. 输入平面文件:大约总大小(以Gb为单位)。这些是如何组织的,例如通过记录?每个文件都包含不同的字段,还是每个文件都有一些记录,每个文件中都有所有字段?
  5. 您是否曾经根据条件选择行(记录)的子集(例如,选择字段A> 5的行)?然后执行某项操作,还是只选择包含所有记录的A,B,C字段(然后执行某项操作)?
  6. 您是否“工作”所有列(成组),还是只用于报告的比例很高(例如,您想保留数据,但无需明确地拉入该列,直到最终结果时间)?

确保至少0.10.1安装了熊猫

逐块读取迭代文件多个表查询

由于pytables已优化为按行操作(这是您要查询的内容),因此我们将为每组字段创建一个表。这样一来,很容易选择一小组字段(它将与一个大表一起使用,但是这样做更有效。我想我将来可能会解决此限制。这是更加直观):(
以下是伪代码。)

import numpy as np
import pandas as pd

# create a store
store = pd.HDFStore('mystore.h5')

# this is the key to your storage:
#    this maps your fields to a specific group, and defines 
#    what you want to have as data_columns.
#    you might want to create a nice class wrapping this
#    (as you will want to have this map and its inversion)  
group_map = dict(
    A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
    B = dict(fields = ['field_10',......        ], dc = ['field_10']),
    .....
    REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),

)

group_map_inverted = dict()
for g, v in group_map.items():
    group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))

读入文件并创建存储(基本上是做什么append_to_multiple):

for f in files:
   # read in the file, additional options may be necessary here
   # the chunksize is not strictly necessary, you may be able to slurp each 
   # file into memory in which case just eliminate this part of the loop 
   # (you can also change chunksize if necessary)
   for chunk in pd.read_table(f, chunksize=50000):
       # we are going to append to each table by group
       # we are not going to create indexes at this time
       # but we *ARE* going to create (some) data_columns

       # figure out the field groupings
       for g, v in group_map.items():
             # create the frame for this group
             frame = chunk.reindex(columns = v['fields'], copy = False)    

             # append it
             store.append(g, frame, index=False, data_columns = v['dc'])

现在,您已将所有表存储在文件中(实际上,您可以根据需要将它们存储在单独的文件中,您可能需要将文件名添加到group_map中,但这可能不是必需的)。

这是获取列并创建新列的方式:

frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
#     select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows

# do calculations on this frame
new_frame = cool_function_on_frame(frame)

# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)

准备进行后期处理时:

# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)

关于data_columns,实际上不需要定义任何 data_columns。它们使您可以根据列来子选择行。例如:

store.select(group, where = ['field_1000=foo', 'field_1001>0'])

在最后的报告生成阶段,它们可能对您来说最有趣(实际上,数据列与其他列是分开的,如果定义太多,这可能会影响效率)。

您可能还想:

  • 创建一个使用字段列表的函数,在groups_map中查找组,然后选择它们并连接结果,以便获得结果框架(本质上就是select_as_multiple所做的事情)。这样,结构对您将非常透明。
  • 在某些数据列上建立索引(使行子设置快得多)。
  • 启用压缩。

如有疑问,请告诉我!


5
感谢您的链接。第二个链接让我有些担心,因为我无法在HDFStore中的表上追加新列?那是对的吗?另外,我还添加了一个有关如何使用此设置的示例。
Zelazny7

4
HDF中的实际结构由您决定。Pytables是面向行的,在创建时具有固定的列。创建表后就无法追加列。但是,您可以创建一个索引与现有表相同的新表。(请参阅文档中的select_as_multiple示例)。这样,您可以创建具有任意大小的对象,同时具有相当高效的查询。使用数据的方式是如何在磁盘上组织数据的关键。给我发送一封清单外的电子邮件,其中包含一个更具体的示例的伪代码。
杰夫

1
我已经更新了我的问题,以回答您的详细问题。我将举一个例子将您发送到清单之外。谢谢!
Zelazny7

12
@Jeff,现在Pandas的版本为0.17.x,Pandas是否已解决上述问题?
ctrl-alt-delete

5
@Jeff热衷于在您的答案中添加快速更新以促进敏捷?
Boud 2013年

137

我认为以上答案都缺少一种我发现非常有用的简单方法。

当我的文件太大而无法加载到内存中时,我将该文件分成多个较小的文件(按行或列)

示例:如果有30天的〜30GB大小的交易数据值得每天将其拆分为一个〜1GB大小的文件。随后,我分别处理每个文件,并在最后汇总结果

最大的优势之一是它允许并行处理文件(多个线程或多个进程)

另一个优点是文件操作(如示例中的添加/删除日期)可以通过常规的shell命令完成,而在更高级/更复杂的文件格式中则无法实现

这种方法无法涵盖所有​​情况,但在许多情况下非常有用


39
同意 毫无疑问
zelusp


66

如果您的数据集介于1到20GB之间,则应该获得具有48GB RAM的工作站。然后,熊猫可以将整个数据集保存在RAM中。我知道这不是您在这里寻找的答案,但是在具有4GB RAM的笔记本电脑上进行科学计算是不合理的。


7
“在具有4GB RAM的笔记本上进行科学计算是不合理的”定义合理。我认为,UNIVAC会有不同的看法。arstechnica.com/tech-policy/2011/09/…–
grisaitis

2
同意!尝试继续在内存中工作,即使预先花费$$。如果您的工作能带来财务回报,那么随着时间的流逝,您将通过提高效率来收回费用。
ansonw

2
在具有48GB RAM的工作站上进行科学计算是不合理的。
Yaroslav Nikitenko,

4
配备61GB / RAM的r4.2xlarge每小时$ .532。您正在进行哪种科学计算,那不那么有价值?听起来很不正常,即使不是很不合理。
rjurney

4
@rjurney对不起,也许我应该删除我的评论。您对“不合理的”科学计算机的判断似乎很主观。我多年来在笔记本电脑上进行科学计算,这对我来说似乎足够了,因为大部分时间我都在编写代码。从编程的角度来看,我的算法比从计算角度来看要困难得多。另外,我非常确定编写可伸缩算法不应依赖当前的硬件限制。您对别人的计算的评论听起来有些冒犯(除了主观性之外),您介意删除这几个词吗?
Yaroslav Nikitenko

58

我知道这是一个旧线程,但是我认为Blaze库值得一试。它是针对此类情况而构建的。

从文档:

Blaze将NumPy和Pandas的可用性扩展到分布式和核外计算。Blaze提供了类似于NumPy ND-Array或Pandas DataFrame的接口,但是将这些熟悉的接口映射到了其他各种计算引擎上,例如Postgres或Spark。

编辑:顺便说一下,它由ContinuumIO和NumPy的作者Travis Oliphant支持。


另一个值得一看的库是GraphLab Create:它具有高效的类似DataFrame的结构,不受内存容量的限制。blog.dato.com/…–
防水

52

pymongo就是这种情况。我还使用python中的sql server,sqlite,HDF,ORM(SQLAlchemy)进行了原型设计。首要的pymongo是基于文档的数据库,因此每个人都是(dict具有属性的)文档。很多人组成一个集合,您可以有很多集合(人,股票市场,收入)。

pd.dateframe-> pymongo注意:我使用chunksizein read_csv使其保持5到10k记录(如果较大,pymongo会删除套接字)

aCollection.insert((a[1].to_dict() for a in df.iterrows()))

查询:gt =大于...

pd.DataFrame(list(mongoCollection.find({'anAttribute':{'$gt':2887000, '$lt':2889000}})))

.find()返回一个迭代器,因此我通常将ichunked其切成更小的迭代器。

由于我通常可以将10个数据源粘贴在一起,因此如何进行联接:

aJoinDF = pandas.DataFrame(list(mongoCollection.find({'anAttribute':{'$in':Att_Keys}})))

然后(就我而言,有时我必须aJoinDF先进行“可合并”操作)。

df = pandas.merge(df, aJoinDF, on=aKey, how='left')

然后,您可以通过下面的update方法将新信息写入您的主要收藏夹。(逻辑收集与物理数据源)。

collection.update({primarykey:foo},{key:change})

在较小的查询中,只需进行非规范化即可。例如,您在文档中有代码,而您仅添加域代码文本并在dict创建文档时进行查找。

现在,您有了一个基于人的漂亮数据集,您可以在每种情况下释放自己的逻辑并添加更多属性。最后,您可以将3个最大记忆键指标读入大熊猫,并进行数据透视/汇总/数据探索。这对我来说适合300万条带有数字/大文本/类别/代码/浮点数/ ...的记录

您还可以使用MongoDB内置的两种方法(MapReduce和聚合框架)。有关聚合框架的更多信息,请参见此处,因为它似乎比MapReduce容易,并且看起来便于进行快速聚合工作。注意,我不需要定义字段或关系,可以将项目添加到文档中。在快速变化的numpy,pandas,python工具集的当前状态下,MongoDB可以帮助我开始工作:)


嗨,我也玩弄了您的示例,尝试插入数据库时​​遇到了此错误:In [96]: test.insert((a[1].to_dict() for a in df.iterrows())) --------------- InvalidDocument: Cannot encode object: 0。任何想法可能有什么问题吗?我的数据框由所有int64 dtypes组成,非常简单。
Zelazny7

2
是的,我对一个简单范围的DF做了同样的事情,而numpy的int64似乎困扰着pymongo。我玩过的所有数据都从CSV转换(通过range()人为进行转换),并且类型很长,因此没有问题。在numpy中,您可以进行转换,但我确实认为这会分散注意力。我必须承认HDF的10.1项目看起来令人兴奋。
brian_the_bungler 2013年

43

我发现这有点晚了,但我遇到了类似的问题(抵押预付款模型)。我的解决方案是跳过熊猫HDFStore层,并使用直接pytables。我将每列保存为最终文件中的单独HDF5阵列。

我的基本工作流程是首先从数据库中获取CSV文件。我用gzip压缩,所以它没有那么大。然后,通过在python中对其进行迭代,将每一行转换为实际数据类型并将其写入HDF5文件,将其转换为面向行的HDF5文件。这花费了数十分钟,但是它不使用任何内存,因为它只是逐行地操作。然后,我将面向行的HDF5文件“转置”为面向列的HDF5文件。

表转置如下:

def transpose_table(h_in, table_path, h_out, group_name="data", group_path="/"):
    # Get a reference to the input data.
    tb = h_in.getNode(table_path)
    # Create the output group to hold the columns.
    grp = h_out.createGroup(group_path, group_name, filters=tables.Filters(complevel=1))
    for col_name in tb.colnames:
        logger.debug("Processing %s", col_name)
        # Get the data.
        col_data = tb.col(col_name)
        # Create the output array.
        arr = h_out.createCArray(grp,
                                 col_name,
                                 tables.Atom.from_dtype(col_data.dtype),
                                 col_data.shape)
        # Store the data.
        arr[:] = col_data
    h_out.flush()

然后读回它就像:

def read_hdf5(hdf5_path, group_path="/data", columns=None):
    """Read a transposed data set from a HDF5 file."""
    if isinstance(hdf5_path, tables.file.File):
        hf = hdf5_path
    else:
        hf = tables.openFile(hdf5_path)

    grp = hf.getNode(group_path)
    if columns is None:
        data = [(child.name, child[:]) for child in grp]
    else:
        data = [(child.name, child[:]) for child in grp if child.name in columns]

    # Convert any float32 columns to float64 for processing.
    for i in range(len(data)):
        name, vec = data[i]
        if vec.dtype == np.float32:
            data[i] = (name, vec.astype(np.float64))

    if not isinstance(hdf5_path, tables.file.File):
        hf.close()
    return pd.DataFrame.from_items(data)

现在,我通常在具有大量内存的计算机上运行此程序,因此我可能对内存使用情况不够谨慎。例如,默认情况下,装入操作将读取整个数据集。

这通常对我有用,但是有点笨拙,我不能使用花式的pytables魔术。

编辑:与默认的记录数组pytables相比,此方法的真正优势在于,我可以使用无法处理表的h5r将数据加载到R中。或者,至少,我无法使其加载异类表。


您介意与我分享一些代码吗?我对如何在推入pytables之前不知道数据类型的情况下如何从某种纯文本格式加载数据感兴趣。同样,您似乎只能使用一种类型的数据。那是对的吗?
Zelazny13年

1
首先,我假设我在加载之前就知道列的类型,而不是试图从数据中猜测。我保存了带有列名和类型的JSON“数据规范”文件,并在处理数据时使用它。(该文件通常是一些糟糕的BCP输出,没有任何标签。)我使用的数据类型是字符串,浮点数,整数或每月日期。我通过保存枚举表将字符串转换为整数,并将日期转换为整数(2000年以后的月份),因此数据中只剩下整数和浮点数以及枚举。我现在将浮点数另存为float64,但是我尝试了float32。
Johann Hibschman 2013年

1
如果您有时间,请尝试使用R进行外部兼容:pandas.pydata.org/pandas-docs/dev/…,如果有困难,也许我们可以进行调整
Jeff

如果可以的话,我会尝试的。rhdf5是一种痛苦,因为它是生物导体包装,而不是像h5r一样处于CRAN上。我受我们的技术架构团队的支配,上次我要求rhdf5出现问题。无论如何,使用OLAP存储面向行而不是面向列似乎是一个错误,但是现在我正在四处逛逛。
Johann Hibschman

38

我发现对大型数据用例有用的一个技巧是通过将浮点精度降低到32位来减少数据量。它并非在所有情况下都适用,但是在许多应用程序中,64位精度过高,并且节省2倍的内存值得。提出一个显而易见的观点:

>>> df = pd.DataFrame(np.random.randn(int(1e8), 5))
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float64(5)
memory usage: 3.7 GB

>>> df.astype(np.float32).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float32(5)
memory usage: 1.9 GB

26

正如其他人所指出的,若干年后的“外的核心”大熊猫相当于已经出现:DASK。尽管dask并不是熊猫及其所有功能的直接替代品,但它出于以下几个原因而脱颖而出:

Dask是一个灵活的用于分析计算的并行计算库,针对动态任务调度进行了优化,以针对“大数据”集合(如并行数组,数据框和列表)的交互式计算工作负载进行动态任务调度,这些列表将诸如NumPy,Pandas或Python迭代器之类的通用接口扩展为更大的-非内存或分布式环境,并可以从便携式计算机扩展到群集。

达斯克强调以下优点:

  • 熟悉:提供并行的NumPy数组和Pandas DataFrame对象
  • 灵活:提供任务调度界面,用于更多自定义工作负载并与其他项目集成。
  • 本机:通过访问PyData堆栈,在Pure Python中启用分布式计算。
  • 快速:以低开销,低延迟和快速数值算法所需的最少序列化操作
  • 扩大规模:在具有1000个核心的集群上灵活运行缩小规模:在单个过程中轻松设置并在笔记本电脑上运行
  • 响应式:设计时考虑了交互式计算,可提供快速反馈和诊断以帮助人类

并添加一个简单的代码示例:

import dask.dataframe as dd
df = dd.read_csv('2015-*-*.csv')
df.groupby(df.user_id).value.mean().compute()

替换这样的一些熊猫代码:

import pandas as pd
df = pd.read_csv('2015-01-01.csv')
df.groupby(df.user_id).value.mean()

并且特别值得注意的是,通过该concurrent.futures界面提供了用于提交自定义任务的通用基础架构:

from dask.distributed import Client
client = Client('scheduler:port')

futures = []
for fn in filenames:
    future = client.submit(load, fn)
    futures.append(future)

summary = client.submit(summarize, futures)
summary.result()

我已经添加了此答案,因为@Private的帖子会定期在建议的删除列表中显示内容和长度。
wp78de

17

在这里还值得一提的是Ray
它是一个分布式计算框架,它以分布式方式自己实现了对熊猫的实现。

只需替换pandas导入,代码应该可以正常运行:

# import pandas as pd
import ray.dataframe as pd

#use pd as usual

可以在这里阅读更多详细信息:

https://rise.cs.berkeley.edu/blog/pandas-on-ray/


16

另一种变化

在熊猫中完成的许多操作也可以作为db查询来完成(sql,mongo)

使用RDBMS或mongodb,您可以在数据库查询中执行某些聚合(针对大型数据进行了优化,并有效地使用了缓存和索引)

以后,您可以使用熊猫进行后期处理。

这种方法的优点是,您可以在处理大型数据时获得数据库优化,同时仍可以使用高级声明性语法定义逻辑-无需处理决定在内存中做什么和做什么的细节。的核心。

尽管查询语言和熊猫语言不同,但是将部分逻辑从一个逻辑转换到另一个逻辑通常并不复杂。


11

如果您走创建数据管道的简单路径,请将该路径分解为多个较小的文件,请考虑使用Ruffus


9

我最近遇到了类似的问题。我发现简单地读取数据并将数据块追加到同一csv时效果很好。我的问题是,使用某些列的值,根据另一张表中的信息添加日期列。这可能会帮助那些对dask和hdf5感到困惑的人,但更熟悉像我这样的熊猫。

def addDateColumn():
"""Adds time to the daily rainfall data. Reads the csv as chunks of 100k 
   rows at a time and outputs them, appending as needed, to a single csv. 
   Uses the column of the raster names to get the date.
"""
    df = pd.read_csv(pathlist[1]+"CHIRPS_tanz.csv", iterator=True, 
                     chunksize=100000) #read csv file as 100k chunks

    '''Do some stuff'''

    count = 1 #for indexing item in time list 
    for chunk in df: #for each 100k rows
        newtime = [] #empty list to append repeating times for different rows
        toiterate = chunk[chunk.columns[2]] #ID of raster nums to base time
        while count <= toiterate.max():
            for i in toiterate: 
                if i ==count:
                    newtime.append(newyears[count])
            count+=1
        print "Finished", str(chunknum), "chunks"
        chunk["time"] = newtime #create new column in dataframe based on time
        outname = "CHIRPS_tanz_time2.csv"
        #append each output to same csv, using no header
        chunk.to_csv(pathlist[2]+outname, mode='a', header=None, index=None)

8

我想指出一下Vaex软件包。

Vaex是用于惰性核心数据框架(类似于Pandas)的python库,用于可视化和探索大型表格数据集。它可以在高达每秒十亿(10 9)个对象/行的N维网格上计算统计信息,例如平均值,总和,计数,标准差等。可视化使用直方图,密度图和3d体积渲染完成,从而可以交互式探索大数据。Vaex使用内存映射,零内存复制策略和惰性计算来获得最佳性能(不浪费内存)。

看一下文档:https : //vaex.readthedocs.io/en/latest/ 该API非常接近于熊猫API。


0

为什么选择熊猫?您是否尝试过标准Python

使用标准库python。即使最近发布了稳定版,Pandas也会经常更新。

使用标准的python库,您的代码将始终运行。

一种实现方法是对要存储数据的方式有所了解,并对数据要解决哪些问题。然后绘制一个模式,说明如何组织数据(思考表),这将有助于您查询数据,而不必进行规范化。

您可以充分利用:

  • 字典列表,用于将数据存储在内存中,一个字典为一行,
  • 生成器逐行处理数据,以免RAM溢出,
  • 列出理解以查询您的数据,
  • 利用Counter,DefaultDict,...
  • 使用您选择的任何存储解决方案将数据存储在硬盘上,json可能是其中之一。

随着时间的推移,Ram和HDD越来越便宜,并且标准python 3广泛可用且稳定。


-1

目前,我正在“喜欢”您,只是规模较小,这就是为什么我没有PoC来建议的原因。

但是,我似乎在使用pickle作为缓存系统并将各种功能的执行外包到文件中找到了成功-从我的commando / main文件中执行这些文件。例如,我使用prepare_use.py转换对象类型,将数据集拆分为测试,验证和预测数据集。

用咸菜进行缓存如何工作?我使用字符串来访问动态创建的pickle文件,具体取决于传递了哪些参数和数据集(为此,我尝试捕获并确定程序是否已在运行,使用.shape表示数据集,使用dict表示通过参数)。尊重这些措施,我得到一个String来尝试查找和读取.pickle文件,并且如果找到了该字符串,则可以跳过处理时间以跳转到我现在正在处理的执行。

使用数据库时,我遇到了类似的问题,这就是为什么我在使用此解决方案时感到高兴的原因,但是-有很多限制-例如由于冗余而存储大量的泡菜集。可以使用正确的索引从转换前到更新表进行更新-验证信息可以打开另一本完整的书(我尝试合并爬网的租金数据,基本上在2小时后停止使用数据库-因为我想在之后跳回每个转换过程)

我希望我的2美分能以某种方式对您有所帮助。

问候。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.