如何使用 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 文件? [关闭]