Python熊猫-读取带有注释标题行的csv

Python熊猫-读取带有注释标题行的csv,python,pandas,csv,parsing,openfoam,Python,Pandas,Csv,Parsing,Openfoam,我想用pandas读取和处理csv文件。文件(如下所示)包含多个标题行,标题行由#标记指示。我可以使用 将熊猫作为pd导入 file=“data.csv” data=pd.read\u csv(文件,分隔符=“\s+”, 名称=[“时间”、“Cd”、“Cs”、“Cl”、“CmRoll”、“CmPitch”、“CmYaw”、“Cd(f)”, "Cd(r),"Cs(f),"Cs(r),"Cl(f),, skiprows=13) 但是,我有很多这样的文件,它们的头名不同,我不想手动命名它们(Time

我想用pandas读取和处理csv文件。文件(如下所示)包含多个标题行,标题行由
#
标记指示。我可以使用

将熊猫作为pd导入
file=“data.csv”
data=pd.read\u csv(文件,分隔符=“\s+”,
名称=[“时间”、“Cd”、“Cs”、“Cl”、“CmRoll”、“CmPitch”、“CmYaw”、“Cd(f)”,
"Cd(r),"Cs(f),"Cs(r),"Cl(f),,
skiprows=13)
但是,我有很多这样的文件,它们的头名不同,我不想手动命名它们(
Time-Cd-Cs…
)。此外,每个文件之间的注释行数也不同。所以我想自动化这项任务

在将数据传递到数据帧之前,我必须在这里使用正则表达式之类的东西吗

谢谢你的建议

是的,标题名称也以
#
开头

data.csv:

# Force coefficients    
# dragDir               : (9.9735673312816520e-01 7.2660490528994301e-02 0.0000000000000000e+00)
# sideDir               : (0.0000000000000000e+00 0.0000000000000000e+00 -1.0000000000000002e+00)
# liftDir               : (-7.2660490528994315e-02 9.9735673312816520e-01 0.0000000000000000e+00)
# rollAxis              : (9.9735673312816520e-01 7.2660490528994301e-02 0.0000000000000000e+00)
# pitchAxis             : (0.0000000000000000e+00 0.0000000000000000e+00 -1.0000000000000002e+00)
# yawAxis               : (-7.2660490528994315e-02 9.9735673312816520e-01 0.0000000000000000e+00)
# magUInf               : 4.5000000000000000e+01
# lRef                  : 5.9399999999999997e-01
# Aref                  : 3.5639999999999999e-03
# CofR                  : (1.4999999999999999e-01 0.0000000000000000e+00 0.0000000000000000e+00)
#
# Time                      Cd                          Cs                          Cl                          CmRoll                      CmPitch                     CmYaw                       Cd(f)                       Cd(r)                       Cs(f)                       Cs(r)                       Cl(f)                       Cl(r)                   
5e-06                       1.8990180226147195e+00  1.4919925634649792e-11  2.1950119509976829e+00  -1.1085971520784955e-02 -1.0863798447281650e+00 9.5910040927874810e-03  9.3842303978657482e-01  9.6059498282814471e-01  9.5910041002474442e-03  -9.5910040853275178e-03 1.1126130770676479e-02  2.1838858202270064e+00
1e-05                       2.1428508927716594e+00  1.0045114197556737e-08  2.5051633252700962e+00  -1.2652317494411272e-02 -1.2367567798452046e+00 1.0822379290263353e-02  1.0587731288914184e+00  1.0840777638802410e+00  1.0822384312820453e-02  -1.0822374267706254e-02 1.5824882789843508e-02  2.4893384424802525e+00
...

一点正则表达式可能会有所帮助

这不是最漂亮的解决方案,所以请随意发布更好的解决方案

让我们读取任何文件的前50行,以查找最后出现的哈希值,该哈希值应为列名

  • ^在行的开始处断言位置
  • #
    按字面意思匹配字符(区分大小写)

编辑、处理列名中的
#
。 我们可以分两步来完成

我们可以读取0行,但可以对标题列进行切片

首先从标题行读入文件,但将
header
参数设置为
None
,这样就不会设置任何标题

然后我们可以手动设置列标题

df = pd.read_csv(path_,sep='\s+',skiprows=start_col + 1, header=None)
df.columns = pd.read_csv(path_,sep='\s+',skiprows=start_col,nrows=0).columns[1:]

print(df)

       Time        Cd            Cs        Cl    CmRoll   CmPitch     CmYaw  \
0  0.000005  1.899018  1.491993e-11  2.195012 -0.011086 -1.086380  0.009591   
1  0.000010  2.142851  1.004511e-08  2.505163 -0.012652 -1.236757  0.010822   

      Cd(f)     Cd(r)     Cs(f)     Cs(r)     Cl(f)     Cl(r)  
0  0.938423  0.960595  0.009591 -0.009591  0.011126  2.183886  
1  1.058773  1.084078  0.010822 -0.010822  0.015825  2.489338 

在读取文件之前提取头文件怎么样? 我们只假设标题行以
#
开头。头的提取及其在文件中的位置是自动的。我们还确保读取的行数不超过所需的行数(第一行数据除外)


这样,您还可以处理其他标题行。它还提供了头在文件中的位置。

为了简化它,并节省时间而不使用循环,您可以为
#
注释行创建2个数据帧,以及其他数据帧。 从这些注释行中选取最后一行-这是您的标题,然后使用
concat()
合并数据帧和此标题。如果有必要将第一行指定为标题,也可以使用
df.columns=df.iloc[0]

df = pd.DataFrame({
    'A':['#test1 : (000000)','#test1 (000000)','#test1 (000000)','#test1 (000000)','#Time (000000)','5e-06','1e-05'],
})
print(df)
   

                A
0  #test1 : (000000)
1    #test1 (000000)
2    #test1 (000000)
3    #test1 (000000)
4     #Time (000000)
5              5e-06
6              1e-05

df_header = df[df.A.str.contains('^#')]
print(df_header)
         

          A
0  #test1 : (000000)
1    #test1 (000000)
2    #test1 (000000)
3    #test1 (000000)
4     #Time (000000)
df_data = df[~df.A.str.contains('^#')]
print(df_data)
       A
5  5e-06
6  1e-05

df = (pd.concat([df_header.iloc[[-1]],df_data])).reset_index(drop=True)
df.A=df.A.str.replace(r'^#',"")



print(df)
          

     A
0  Time (000000)
1          5e-06
2          1e-05

假设注释总是以单个“#”开头,并且标题位于最后一个注释行中:

导入csv
def read_注释(csv_文件):
对于csv_文件中的行:
如果行[0]='#':
产量行.拆分('#')[1].strip()
def get_last_commented_行(文件名):
将open(文件名为“r”,换行符为“”)设为f:
取消注释的注释行=[csv.reader中的行对行(读取注释(f))]
标题=取消注释的\u行[-1]
skiprows=len(非对称线)
返回标题,skiprows
标题,skiprows=get\u last\u commented\u行(路径)
pd.read_csv(路径,名称=标题,skiprows=skiprows)

这应该可以做到,它简单高效,将变量保持在最小值,除了文件名之外不需要任何输入

with open(file, 'r') as f:
    for line in f:
        if line.startswith('#'):
            header = line
        else:
            break #stop when there are no more #

header = header[1:].strip().split()

data = pd.read_csv(file, delimiter="\s+", comment='#', names=header)

您首先打开文件,然后仅读取注释行(这将非常快速且节省内存)。最后一个有效行将是最终标题,它将被清除并转换为列表。最后,使用
pandas.read_csv()
comment='.
打开文件,这将跳过注释行,和
names=header

你的头总是在最后一行的位置吗?实际上大多数文件-所以是的:)EDIT:是的。这无法处理头名行上的
注释标记,这导致最后一列中出现
NaN
,因为熊猫认为首字母
也是头名。但你的解决方案对我来说是个好的开始。谢谢。@Sunsheep实际上是你的熟食
'\s+'
?是的。你的编辑效果很好,但在我看来,Stefans的答案更简单:)然而,这些文件很大,所以你只读取前50行的解决方案非常方便。这很好。非常感谢。但是,由于我的文件很大,所以我将只阅读@Manakin@Sunsheep,我的解决方案只读取标题行+第一个数据行。所以如果你的页眉是13行,你会读14行,效果很好。谢谢类似于Stefans的回答。他跑快了一点:)
df = pd.DataFrame({
    'A':['#test1 : (000000)','#test1 (000000)','#test1 (000000)','#test1 (000000)','#Time (000000)','5e-06','1e-05'],
})
print(df)
   

                A
0  #test1 : (000000)
1    #test1 (000000)
2    #test1 (000000)
3    #test1 (000000)
4     #Time (000000)
5              5e-06
6              1e-05

df_header = df[df.A.str.contains('^#')]
print(df_header)
         

          A
0  #test1 : (000000)
1    #test1 (000000)
2    #test1 (000000)
3    #test1 (000000)
4     #Time (000000)
df_data = df[~df.A.str.contains('^#')]
print(df_data)
       A
5  5e-06
6  1e-05

df = (pd.concat([df_header.iloc[[-1]],df_data])).reset_index(drop=True)
df.A=df.A.str.replace(r'^#',"")



print(df)
          

     A
0  Time (000000)
1          5e-06
2          1e-05
with open(file, 'r') as f:
    for line in f:
        if line.startswith('#'):
            header = line
        else:
            break #stop when there are no more #

header = header[1:].strip().split()

data = pd.read_csv(file, delimiter="\s+", comment='#', names=header)