如何使用 python 对 CSV 文件的多列进行排序?

Posted

技术标签:

【中文标题】如何使用 python 对 CSV 文件的多列进行排序?【英文标题】:How do you sort multiple columns of a CSV file using python? 【发布时间】:2011-12-23 05:56:35 【问题描述】:

我在弄清楚如何将大型数据集分类为更有用的数据时遇到问题。

CSV 格式的原始文件如下所示 - 数据表示 x、y、z 位置,最后是能量。 x,y,z 坐标分布很广,这是下面的一个小sn-p——基本上它是对一个体积的能量搜索。

-2.800000,-1.000000,5.470000,-0.26488315
-3.000000,1.000000,4.070000,-0.81185718
-2.800000,-1.000000,3.270000,1.29303723
-2.800000,-0.400000,4.870000,-0.51165026

不幸的是,在必要的四个维度上绘制非常困难,所以我需要修剪这些数据。我想这样做,我会将体积变成最低能量 z 轴上的表面。在较小的数据集上,这很简单,在 Excel 中按 X、Y 和能量排序,然后删除最低能量以上的所有能量。这对于小型数据集来说很容易,但很快就会出现问题。

我尝试了各种方法,例如拆分 csv 和使用 sort 命令,但我运气不佳。任何有关如何解决此问题的建议将不胜感激。

【问题讨论】:

【参考方案1】:

我认为 numpy 的 lexsort 将满足您的排序需求。

总的来说,我认为您的步骤是:

    将csv读入numpy数组——你试过python的csv package还是numpy的genfromtext() function?

    使用 lexsort 进行排序

    剪掉不必要的行

编辑:见this related SO question。

【讨论】:

这看起来很有希望,它似乎是一种比我尝试的更简单的方法。可能有一种创造性的方式对其进行排序,以便所有不需要的行都位于底部。【参考方案2】:

将数据读入带有csv.reader 的元组列表后,按(x, y) 值对数据进行排序。为清楚起见,请使用named tuples 来标识字段。

然后使用itertools.groupby对相关的(x, y)数据点进行聚类。对于每个组,使用min 隔离能量最低的组:

>>> import csv, collections, itertools

>>> raw_data = '''\
-2.800000,-1.000000,5.470000,-0.26488315
-3.000000,1.000000,4.070000,-0.81185718
-2.800000,-1.000000,3.270000,1.29303723
-2.800000,-0.400000,4.870000,-0.51165026
'''.splitlines()

>>> Sample = collections.namedtuple('Sample', ['x', 'y', 'z', 'energy'])
>>> data = [Sample(*row) for row in csv.reader(raw_data)]
>>> data.sort(key=lambda s: (s.x, s.y))
>>> for xy, group in itertools.groupby(data, key=lambda s: (s.x, s.y)):
        print min(group, key=lambda s: s.energy)


Sample(x='-2.800000', y='-0.400000', z='4.870000', energy='-0.51165026')
Sample(x='-2.800000', y='-1.000000', z='5.470000', energy='-0.26488315')
Sample(x='-3.000000', y='1.000000', z='4.070000', energy='-0.81185718')

【讨论】:

当我使用这种方法时,我无法弄清楚如何将样本中的其他能量剪掉。因此,在您的输出中,我希望保留 1、2 和 4,但删除第 3 行。 刚刚编辑了答案以显示使用列表推导过滤掉不需要的样本。 是的,但并非总是这样,每个特定的 x,y 坐标都需要从可能的 z 坐标中挑选出的最低能量,并且这并不总是正值或存在其他负值。目前我正在尝试将线条分成相同的 x,y 分组,然后删除除最低能量之外的所有分组。 好的,我已经编辑以按 (x, y) 坐标显示分组并找到每个组的最小值。按浮点值分组时要小心,即使是很小的差异也会创建不同的组。【参考方案3】:

这就是您在对 Raymond 的回答的评论中提出的问题 - 仅返回每个 x, y 对中具有最低 z 的行:

from operator import itemgetter
from itertools import groupby
from csv import reader


def min_z(iterable):
    # the data converted from strings to numbers
    floats = [[float(n) for n in row] for row in iterable]
    # the data sorted by x, y, z
    floats.sort(key=lambda (x, y, z, e): (x, y, z))
    # group the data by x, y
    grouped_floats = groupby(floats, key=itemgetter(slice(0, 2)))
    # return the first item from each group
    # because the data is sorted
    # the first item is the smallest z for the x, y group
    return [next(rowgroup) for xy, rowgroup in grouped_floats]


data = """-2.800000,-1.000000,5.470000,-0.26488315
-3.000000,1.000000,4.070000,-0.81185718
-2.800000,-1.000000,3.270000,1.29303723
-2.800000,-0.400000,4.870000,-0.51165026""".splitlines()


print min_z(reader(data))

打印:

[[-3.0, 1.0, 4.07, -0.81185718], 
 [-2.8, -1.0, 3.27, 1.29303723], 
 [-2.8, -0.4, 4.87, -0.51165026]]

【讨论】:

这似乎很好用,我正在实施的两个问题是 z 需要是最小能量,而目前你正在获得最大值。 不确定你的意思..它按第 1 列和第 2 列分组,并为每组取第 3 列的最小值。你想在第 4 列而不是第 3 列分组吗? 我稍微修改了一下。如果您想按不同的列排序,只需将 x, y, z 更改为 x, y, e 或其他任何内容。 啊,结果现在更有意义了。是的,第四列是我们需要取的最小值。 完美运行只需要让它打开一个csv文件!感谢您的帮助。

以上是关于如何使用 python 对 CSV 文件的多列进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sklearn 对 CSV 文件中的多列进行一次热编码?

如何按范围对csv文件中的列进行分组并使用python绘制直方图?

使用 Python 从 csv 文件中的字符串搜索中打印多列

如何使用 Qt 将两个单列 csv 文件合并为一个多列 csv 文件? [关闭]

如何使用BeautifulSoup中的Python将单行中多列分隔的数据导出为.csv或.xls?

Python Pandas 对多列进行值计数并根据结果生成图表