如何对排序的文件进行分组并保留分组顺序 - python

我有一个大型CSV文件,该文件按其几个列排序,我们称这些列为sorted_columns
我想对这些sorted_columns进行分组,并对每个分组应用一些逻辑。

该文件不完全适合内存,因此我想分块读取它并在每个块上执行groupby

我注意到的是,即使文件已按这些列排序,也不会保留组的顺序。

最终,这就是我想要做的:

import pandas as pd

def run_logic(key, group):
    # some logic
    pass

last_group = pd.DataFrame()
last_key = None

for chunk_df in df:
    grouped_by_df = chunk_df.groupby(sorted_columns, sort=True)

    for key, group in grouped_by_df:
        if last_key is None or last_key == key:
            last_key = key
            last_group = pd.concat([last_group, group])
        else:  # last_key != key
            run_logic(last_key, last_group)
            last_key = key
            last_group = group.copy()
run_logic(last_key, last_group)

但这是行不通的,因为groupby不能保证保留组的顺序。如果两个连续的块中都存在相同的key,则不能保证在第一个块中它将是最后一个组,在下一个块中它将是第一个。
我尝试将groupby更改为使用sort=False,还尝试更改列的顺序,但这没有帮助。

如果密钥已经在原始文件中排序,那么有人对如何保留组的顺序有任何想法吗?

还有其他方法可以一次从文件中读取完整的组吗?

参考方案

itertools.groupby

将返回键和该键分组的所有值的迭代器。
如果您的文件已经按照所需的键进行排序,那么就可以了。
groupby函数将为您处理几乎所有事情。

从documentation:

groupby()的操作类似于Unix中的uniq过滤器。每当键函数的值更改时,它都会生成一个中断或新组(这就是为什么通常需要使用相同的键函数对数据进行排序的原因)。这种行为与SQL的GROUP BY有所不同,后者会按通用元素的输入顺序来聚合它们。

run_logic是要应用于记录组的任何业务逻辑。这个例子只是简单地计算迭代器中的观察次数。

data_iter只需为每个CSV发出1行。只要您的文件按所需的字段排序,就不需要将整个文件读入内存。

块使用groupby通过输入行的前3个字段对输入迭代器进行分组。它产生键和与该键关联的值的相应迭代器。

#!/usr/bin/env python3

import csv
from itertools import groupby

def run_logic(key, group):
    cntr = 0
    for rec in group:
        cntr = cntr + 1
    return (key, cntr)


def data_iter(filename):
    with open(filename, "r") as fin:
        csvin = csv.reader(fin)
        for row in csvin:
            yield row


def chunks(diter):
    for chunk, iter_ in groupby(diter, key=lambda x: x[0:3]):
        yield (chunk, iter_)


if __name__ == "__main__":
    csviter = data_iter("test.csv")
    chunk_iter = chunks(csviter)
    for chunk, iter_ in chunk_iter:
        print(run_logic(chunk, iter_))

输入数据

['1', '1', '1', 'a', 'a', 'a', 'a']  
['1', '1', '1', 'b', 'b', 'b', 'b']  
['1', '1', '1', 'c', 'c', 'c', 'c']  
['1', '1', '1', 'd', 'd', 'd', 'd']  
['1', '1', '1', 'e', 'e', 'e', 'e']  
['2', '1', '1', 'a', 'a', 'a', 'a']  
['2', '1', '1', 'd', 'd', 'd', 'd']  
['2', '1', '1', 'e', 'e', 'e', 'e']  
['2', '1', '1', 'b', 'b', 'b', 'b']  
['2', '1', '1', 'c', 'c', 'c', 'c']  
['3', '1', '1', 'e', 'e', 'e', 'e']  
['3', '1', '1', 'b', 'b', 'b', 'b']  
['3', '1', '1', 'c', 'c', 'c', 'c']  
['3', '1', '1', 'a', 'a', 'a', 'a']  
['3', '1', '1', 'd', 'd', 'd', 'd']

分组数据

组:['1','1','1']

['1', '1', '1', 'a', 'a', 'a', 'a']
['1', '1', '1', 'b', 'b', 'b', 'b']
['1', '1', '1', 'c', 'c', 'c', 'c']
['1', '1', '1', 'd', 'd', 'd', 'd']
['1', '1', '1', 'e', 'e', 'e', 'e']

组:['2','1','1']

['2', '1', '1', 'a', 'a', 'a', 'a']
['2', '1', '1', 'd', 'd', 'd', 'd']
['2', '1', '1', 'e', 'e', 'e', 'e']
['2', '1', '1', 'b', 'b', 'b', 'b']
['2', '1', '1', 'c', 'c', 'c', 'c']

组:['3','1','1']

['3', '1', '1', 'e', 'e', 'e', 'e']
['3', '1', '1', 'b', 'b', 'b', 'b']
['3', '1', '1', 'c', 'c', 'c', 'c']
['3', '1', '1', 'a', 'a', 'a', 'a']
['3', '1', '1', 'd', 'd', 'd', 'd']

应用业务逻辑

组:['1','1','1']

(['1', '1', '1'], 5)

组:['2','1','1']

(['2', '1', '1'], 5)

组:['3','1','1']

(['3', '1', '1'], 5)

在返回'Response'(Python)中传递多个参数 - python

我在Angular工作,正在使用Http请求和响应。是否可以在“响应”中发送多个参数。角度文件:this.http.get("api/agent/applicationaware").subscribe((data:any)... python文件:def get(request): ... return Response(seriali…

Python exchangelib在子文件夹中读取邮件 - python

我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…

python pandas:按行对条件进行分组 - python

我有一个大的pandas数据框,试图从中形成一些行的对。我的df如下所示:object_id increment location event 0 1 d A 0 2 d B 0 3 z C 0 4 g A 0 5 g B 0 6 i C 1 1 k A 1 2 k B ... ... ... ... 对象ID描述特定的对象。增量是每次发生某事(跟踪订单)时…

Python-Excel导出 - python

我有以下代码:import pandas as pd import requests from bs4 import BeautifulSoup res = requests.get("https://www.bankier.pl/gielda/notowania/akcje") soup = BeautifulSoup(res.cont…

pandas DataFrame:根据另一列中的布尔值计算总和 - python

我对Python相当陌生,我尝试在pandas中模拟以下逻辑我目前正在循环抛出行,并希望对前几行的AMOUNT列中的值求和,但只求和最后一次看到的“ TRUE”值。实际数据似乎效率低下(我的数据框大约有500万行)?想知道用Python处理这种逻辑的有效方法是什么?逻辑:逻辑是,如果FLAG为TRUE,我想对前几行的AMOUNT列中的值求和,但只求和最后一次…