从CSV中,如何将相似的数据分组在一起?

3

我有一些数据需要分组:

Serial_Num     Latitude Longitude
1950004S11059   -11.1   59.1
1950004S11059   -11.6   57.8
1950004S11059   -12.4   56
1950004S11059   -13.2   54.6
1950004S11059   -13.8   53.8
1950004S11059   -14.8   52.7
1950004S11059   -15.9   52
1950004S11059   -18.3   52.4
1950004S11059   -20     54
1950004S11059   -22.1   55.9
1950004S11059   -26.2   59.8
1950012S14150   -14     146.9
1950012S14150   -14.4   145.8
1950012S14150   -14.9   145.4
1950012S14150   -15.8   145.6
1950012S14150   -18.9   149.1
1950012S14150   -22.3   152.5
1950013S14139   -16     139
1950013S14139   -16.3   139

那么简单来说,对于每个唯一的“Serial_Num”,我想要坐标。我期望得到类似于以下内容:
1950004S11059: {"GPS": (-11.1 , 59.1) , (-11.6, 57.8) , (-12.4, 56), ..., (-26.2, 59.8)}

然后我可以循环遍历每个Serial_Num的GPS坐标并进行绘制。
我有一些已经在其他地方使用的脚本,但主要依赖于使用csv数据设置字典,以Serial_Num为键。
然而,csv中的数据是顺序的,顺序很重要。
如何输出每个Serial_Num的坐标列表,并按照它们在CSV中的顺序排列?
编辑:我现在正在查看Pandas,因为它有一个groupBy方法可能会有所帮助。
2个回答

2

给定

一个名为foo.csv的文件:

Serial_Num     Latitude Longitude
1950004S11059   -11.1   59.1
1950004S11059   -11.6   57.8
1950004S11059   -12.4   56
1950004S11059   -13.2   54.6
1950004S11059   -13.8   53.8
1950004S11059   -14.8   52.7
1950004S11059   -15.9   52
1950004S11059   -18.3   52.4
1950004S11059   -20     54
1950004S11059   -22.1   55.9
1950004S11059   -26.2   59.8
1950012S14150   -14     146.9
1950012S14150   -14.4   145.8
1950012S14150   -14.9   145.4
1950012S14150   -15.8   145.6
1950012S14150   -18.9   149.1
1950012S14150   -22.3   152.5
1950013S14139   -16     139
1950013S14139   -16.3   139

以下是用于将数据解析为元组(序列号,坐标)的一些代码:

import csv
import collections as ct


def read_file(fname):
    with open(fname) as f:
        reader = csv.reader(f)
        next(reader)
        for line in reader:
            #line = [x for x in line[0].split(" ") if x]
            yield line[0], tuple(map(float, line[1:]))

代码

我们建立了一组defaultdicts的嵌套:

data = ct.defaultdict(dict)
for serial, coords in (read_file("foo.csv")):
    if serial not in data:
        dd = ct.defaultdict(list)
    dd["GPS"].append(coords)
    data[serial] = dd

dict(data)

输出

{'1950004S11059': defaultdict(list,
             {'GPS': [
               (-11.1, 59.1),
               (-11.6, 57.8),
               (-12.4, 56.0),
               (-13.2, 54.6),
               (-13.8, 53.8),
               (-14.8, 52.7),
               (-15.9, 52.0),
               (-18.3, 52.4),
               (-20.0, 54.0),
               (-22.1, 55.9),
               (-26.2, 59.8)]}),
 '1950012S14150': defaultdict(list,
             {'GPS': [
               (-14.0, 146.9),
               (-14.4, 145.8),
               (-14.9, 145.4),
               (-15.8, 145.6),
               (-18.9, 149.1),
               (-22.3, 152.5)]}),
 '1950013S14139': defaultdict(list, 
             {'GPS': [
               (-16.0, 139.0), 
               (-16.3, 139.0)]})}

我尝试使用我的.csv文件(而不是.txt文件)进行操作,它成功地为每个唯一的Serial_Num添加了一个条目,但对于每个键返回了空值。2017161N13119 defaultdict(<class 'list'>, {'GPS': [(), (), (), (), (), (), (), (), (), (), (), (), (), ()]}) - BruceWayne
我将文件扩展名替换为.csv,这对我起作用了。尝试将文件重命名为.txt。我怀疑你的CSV没有正确分隔列。 - pylang
你尝试将它保存为 .txt 文件了吗? - pylang
是的 :/ ...只是空信息。顺便说一下,我正在完全使用您的代码,并在末尾添加了print(data) - BruceWayne
好的。现在应该已经修复了,可以生成真正的CSV文件了。 - pylang
显示剩余2条评论

2
这是一种方法。下面对每个步骤进行细分。
import pandas as pd

df = pd.read_csv('file.csv', delim_whitespace=True)
df['GPS'] = list(zip(df.Latitude, df.Longitude))
df.groupby('Serial_Num')['GPS'].apply(list).to_dict()

读取数据

df = pd.read_csv('file.csv', delim_whitespace=True)

#        Serial_Num  Latitude  Longitude
# 0   1950004S11059     -11.1       59.1
# 1   1950004S11059     -11.6       57.8
# 2   1950004S11059     -12.4       56.0
# 3   1950004S11059     -13.2       54.6
# 4   1950004S11059     -13.8       53.8
# 5   1950004S11059     -14.8       52.7

创建元组列
df['GPS'] = list(zip(df.Latitude, df.Longitude))

#        Serial_Num  Latitude  Longitude             GPS
# 0   1950004S11059     -11.1       59.1   (-11.1, 59.1)
# 1   1950004S11059     -11.6       57.8   (-11.6, 57.8)
# 2   1950004S11059     -12.4       56.0   (-12.4, 56.0)
# 3   1950004S11059     -13.2       54.6   (-13.2, 54.6)
# 4   1950004S11059     -13.8       53.8   (-13.8, 53.8)
# 5   1950004S11059     -14.8       52.7   (-14.8, 52.7)

创建字典

df.groupby('Serial_Num')['GPS'].apply(list).to_dict()

# {'1950004S11059': [(-11.1, 59.100000000000001),
#                    (-11.6, 57.799999999999997),
#                    (-12.4, 56.0),
#                    (-13.199999999999999, 54.600000000000001),
#                    (-13.800000000000001, 53.799999999999997),
#                    (-14.800000000000001, 52.700000000000003),
#                    (-15.9, 52.0),
#                    (-18.300000000000001, 52.399999999999999),
#                    (-20.0, 54.0),
#                    (-22.100000000000001, 55.899999999999999),
#                    (-26.199999999999999, 59.799999999999997)],
#  '1950012S14150': [(-14.0, 146.90000000000001),
#                    (-14.4, 145.80000000000001),
#                    (-14.9, 145.40000000000001),
#                    (-15.800000000000001, 145.59999999999999),
#                    (-18.899999999999999, 149.09999999999999),
#                    (-22.300000000000001, 152.5)],
#  '1950013S14139': [(-16.0, 139.0), (-16.300000000000001, 139.0)]}

是的!!太棒了。我对Pandas非常陌生,但是看起来df.Latitude中的“Latitude”不是Pandas中的设置方法/单词,而是文件中的文字标题,是吗?所以如果我还有州名在“State”下面,我可以这样做:zip(df.State,df.Latitude,df.Longitude),对吧?这三行代码中有很多内容,我需要仔细研究,但是非常感谢您的帖子/回答! - BruceWayne
@pylang - 当我尝试使用 .csv 文件时,出现以下错误:pandas.errors.ParserError: Error tokenizing data. C error: Expected 5 fields in line 901, saw 6 - BruceWayne
1
@BruceWayne,看起来你的csv文件有问题。你能在文本编辑器中打开并查看第901行吗?可能是逗号放错了位置或类似的问题。使用pandas [error_bad_lines=False]可以忽略错误行,但这意味着你的数据可能不完整。 - jpp
我也是这么想的 - 但看起来好像没有多余的逗号,对吧?请参见屏幕截图 - BruceWayne
我会将这行代码复制到一个单独的文件中,然后使用pandas读取并查看结果。 - jpp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接