将复杂的csv文件读入numpy数组

时间:2016-05-05 11:02:22

标签: python csv numpy

我有这样的csv文件;

rgb-28.ppm
rgb-29.ppm (214.75142, 45.618622, 319.0, 152.53371, 0.91839749)
rgb-30.ppm (235.09999, 47.999729, 319.0, 147.49998, 0.88473213)  (281.05219, 54.649971, 319.0, 108.78567, 0.61637461)

在每一行上都有一个文件的名称,并且有一个或多个属于该文件的元组。

我想将此csv文件读取如下。

在每一行上,第一列将涉及文件的名称。接下来的列将涉及元组。如果没有任何元组,该列将为空。如果有元组,则元组将占据列。

当我想要读取此文件时如下;

contours = genfromtxt(path, delimiter=' ')

我收到以下错误:

  

第#36098行(有6列而不是1列)

如何将这种文件读入csv?

谢谢,

2 个答案:

答案 0 :(得分:2)

试试这个。这个想法是,从输入文件中找到具有最大列数的行。使用此方法,构造动态列列表名称。将此列列表作为列名传递给Pandas。正如评论中所提到的,numpy在处理缺失值方面效率不高。一旦数据在DataFrame中,使用列C1,C2等删除不需要的字符,然后使用str.split将数字转换为列表中的数字。

import pandas as pd

l_max_col_nos = 0
l_f = open('data.csv','r')
for each_line in l_f:
    l_split = len(each_line.split('\t'))
    if l_split > l_max_col_nos:
        l_max_col_nos = l_split
l_f.close()
l_column_list = []
for each_i in xrange(l_max_col_nos):
    l_column_list.append('C' + str(each_i))
print l_column_list
l_df = pd.read_csv('data.csv',sep='\t',header=None,names=l_column_list)
print l_df

print l_df['C1'].str.replace(')','').str.replace('(','').str.replace('\s','').str.split(',')

<强>输出

['C0', 'C1', 'C2']
           C0                                                 C1  \
0  rgb-28.ppm                                                NaN
1  rgb-29.ppm  (214.75142, 45.618622, 319.0, 152.53371, 0.918...
2  rgb-30.ppm  (235.09999, 47.999729, 319.0, 147.49998, 0.884...

                                                  C2
0                                                NaN
1                                                NaN
2  (281.05219, 54.649971, 319.0, 108.78567, 0.616...
0                                                  NaN
1    [214.75142, 45.618622, 319.0, 152.53371, 0.918...
2    [235.09999, 47.999729, 319.0, 147.49998, 0.884...
dtype: object

答案 1 :(得分:2)

当您使用genfromtxt(path, delimiter=' ')时,它会读取每一行,并在分隔符上将其拆分。如果没有进一步的规范,它会将第一行中的分割字符串数作为所有行的预期数量。

第一行只有一个字符串 - 所以它希望一列完全失效。

第二行有该字符串,但它也有5个数字字符串。是的,它们被()包裹并以,分隔;但它们也被空间隔开。 genfromtxt无法处理()

然后第3行有2个()块。

csv.reader可以处理引用的字符串,但我认为它不能将()视为"..."

您的解析目标不适合数组或表。听起来你期望每行有一些'列'变量,并且每个这样的'列'将包含这个5个数字元组。这不算。是的,您可以将该结构强制转换为对象类型数组,但是这种结构很糟糕。

但是,如果每个数字元组包含5个,我可以看到创建一个文件名为key的字典,并将该行的每个元组作为5列2d数组中的一行。但无论目标结构如何,您都需要找出一条线的方式,例如具有2个元组的线。如何在空格上拆分,而不拆分','?拥有()个群组后,您可以删除(),然后拆分','。 re正则表达式模块可能是最好的工具(我会尝试开发它)。

=======================

可能解析您的示例

从行解析功能开始:

def foo(aline):
    alist = re.split(' \(',aline)
    key = alist[0]
    rest = alist[1:]
    rest = [r.strip().strip(')') for r in rest]
    if len(rest)>0:
       rest = np.array([[float(i) for i in r.split(',')] for r in rest])
    else:    
       rest = None
    return [key, rest]

您的示例文本 - 复制粘贴并分成行

In [310]: txt="""rgb-28.ppm
rgb-29.ppm (214.75142, 45.618622, 319.0, 152.53371, 0.91839749)
rgb-30.ppm (235.09999, 47.999729, 319.0, 147.49998, 0.88473213)  (281.05219, 54.649971, 319.0, 108.78567, 0.61637461)"""

In [311]: txt=txt.splitlines()

In [312]: txt
Out[312]: 
['rgb-28.ppm',
 'rgb-29.ppm (214.75142, 45.618622, 319.0, 152.53371, 0.91839749)',
 'rgb-30.ppm (235.09999, 47.999729, 319.0, 147.49998, 0.88473213)  (281.05219, 54.649971, 319.0, 108.78567, 0.61637461)']

现在通过函数传递每一行:

In [313]: data = []    
In [314]: for line in txt:
   .....:     data.append(foo(line))

In [315]: data
Out[315]: 
[['rgb-28.ppm', None],
 ['rgb-29.ppm',
  array([[ 214.75142   ,   45.618622  ,  319.        ,  152.53371   ,
             0.91839749]])],
 ['rgb-30.ppm',
  array([[ 235.09999   ,   47.999729  ,  319.        ,  147.49998   ,
             0.88473213],
         [ 281.05219   ,   54.649971  ,  319.        ,  108.78567   ,
             0.61637461]])]]

In [316]: data[2][1].shape
Out[316]: (2, 5)

最后一行包含2x5数组中的数据。第一个有None

分裂'('似乎足以处理较大的群组。它会在群组上留下尾随')',但这很容易剥离。剩下的就是将每个组拆分成子串,并将它们转换为浮点数。

如上所述,该函数没有错误检查或健壮性,但它是一个开始。数据可能不完全符合您的要求,但可以根据需要进行重新设计。