我有这样的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?
谢谢,
答案 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
。
分裂'('似乎足以处理较大的群组。它会在群组上留下尾随')',但这很容易剥离。剩下的就是将每个组拆分成子串,并将它们转换为浮点数。
如上所述,该函数没有错误检查或健壮性,但它是一个开始。数据可能不完全符合您的要求,但可以根据需要进行重新设计。