处理CSV数据时如何忽略第一行数据?

141

我想让Python打印CSV数据列中的最小值,但顶行是列号,我不希望Python将顶行考虑在内。如何确保Python忽略第一行?

目前的代码如下:

import csv

with open('all16.csv', 'rb') as inf:
    incsv = csv.reader(inf)
    column = 1                
    datatype = float          
    data = (datatype(column) for row in incsv)   
    least_value = min(data)

print least_value

您能否解释一下您正在做什么,而不仅仅是给出代码?我非常非常新手,希望确保我理解所有内容。


5
您知道您只是在创建一个生成器来返回文件中每行的 1.0 并取最小值吗?最小值将是 1.0 - Wooble
@Wooble 从技术上讲,它是一个生成器的1.0版本。 :) - Danica
@Wooble 很好的发现 - ...datatype(row[column]... 我猜这就是 OP 想要实现的 - Jon Clements
我之前有人帮我写那段代码,我没发现,所以感谢哈哈! - user1496646
18个回答

120
你可以使用 csv 模块的 Sniffer 类的实例来推断 CSV 文件的格式,并且使用内置的 next() 函数仅在必要时跳过第一行头部行:
import csv

with open('all16.csv', 'r', newline='') as file:
    has_header = csv.Sniffer().has_header(file.read(1024))
    file.seek(0)  # Rewind.
    reader = csv.reader(file)
    if has_header:
        next(reader)  # Skip header row.
    column = 1
    datatype = float
    data = (datatype(row[column]) for row in reader)
    least_value = min(data)

print(least_value)

由于您的示例中datatypecolumn是硬编码的,因此处理row时稍微快一些:

    data = (float(row[1]) for row in reader)

注意: 上面的代码适用于Python 3.x。对于Python 2.x,请使用以下行来打开文件,而不是所示内容:

with open('all16.csv', 'rb') as file:

2
不要使用 has_header(file.read(1024)),改为 has_header(file.readline()) 是否更合理?我看到很多人这样写,但我不明白 has_reader() 如何从 CSV 文件的单行中检测是否有标题。 - Anto
1
@Anto:我的答案中的代码基于文档中的“用于嗅探器使用的示例”,因此我认为这是规定的方法。我同意仅基于一行数据进行判断似乎并不总是足够的数据,但由于Sniffer的工作方式没有描述,所以我不知道。顺便说一下,我从来没有见过has_header(file.readline())被使用,即使它大多数时间都有效,出于上述原因,我也会对这种方法持高度怀疑态度。 - martineau
感谢您的输入。然而,使用file.read(1024)在Python的csv库中会生成错误。例如,请参见此处这里 - Anto
如果我想使用csv.DictReader而不是csv.reader,该如何跳过第一行呢?在我的情况下,CSV文件的第一行解释了每列的含义,方便人类阅读。 - user3064538
@Boris:如果文件开头有多行带有字段名称的行,即可选的所谓“标题”行,则它不符合有效的CSV格式。我能想到的唯一办法是,在打开文件后立即调用next(file)跳过它,如果您确定它会出现的话。在将其传递给csv.reader之前,您还需要将文件倒回到该点加上csv.Sniffer检测到的任何标准正常标题。 - martineau
显示剩余3条评论

88

要跳过第一行,只需调用:

next(inf)

在Python中,文件是对行进行迭代的迭代器。


Python文件的简要总结。 - bearcat
你能给一个你找到这个内容的链接吗?有没有关于next()函数参数的文档链接? - Bluetail
@bluetail https://docs.python.org/3/library/functions.html#next - jfs
1
如果第一行中的某个值可能包含换行符\n,那么这种方法就不起作用了。 - user3064538

43

源自Python Cookbook
更简洁的模板代码可能如下:

import csv
with open('stocks.csv') as f:
    f_csv = csv.reader(f) 
    headers = next(f_csv) 
    for row in f_csv:
        # Process row ...

25
在一个类似的用例中,我必须跳过我的实际列名所在行之前的恼人的行。这个解决方案运行良好。首先读取文件,然后将列表传递给csv.DictReader
with open('all16.csv') as tmp:
    # Skip first line (if any)
    next(tmp, None)

    # {line_num: row}
    data = dict(enumerate(csv.DictReader(tmp)))

谢谢Veedrac。很高兴在这里学习,你能建议一些编辑来解决你提到的问题吗?我的解决方案完成了工作,但似乎还可以进一步改进? - Maarten
1
我给你提供了一个编辑,用它替换了代码,这个代码应该是相同的(未经测试)。如果它与您的意思不符,请随时恢复。我仍然不确定为什么您要创建“data”字典,而且这个答案并没有比已接受的答案多出什么内容。 - Veedrac
谢谢Veedrac!看起来非常高效。我发布了我的答案,因为被接受的那个对我无效(现在记不清原因了)。相比于你的建议,使用定义数据= dict()并立即填充它会有什么问题? - Maarten
1
使用 data = dict() 并填充数据并不是错误的,但这样做效率低下且不符合惯用法。此外,即使在这种情况下,也应该使用字典字面量({})和enumerate - Veedrac
1
顺便说一句,如果你想确保我收到通知,应该用“@Veedrac”回复我的帖子,尽管Stack Overflow似乎能够从用户名中猜测出来。(我不写“@Maarten”,因为默认情况下回答者会收到通知。) - Veedrac
如果第一行中的某个值可能包含换行符\n,那么这种方法就不起作用了。 - user3064538

19

通常你会使用 next(incsv) 来使迭代器向前移动一行,这样你就可以跳过标题行。如果你想跳过30行(或其他行数),那么可以使用如下代码:

from itertools import islice
for row in islice(incsv, 30, None):
    # process

8

使用csv.DictReader替代csv.Reader。 如果省略了fieldnames参数,则csvfile的第一行中的值将用作字段名称。然后,您可以使用row ["1"]等访问字段值


5

Python 2.x

csvreader.next()

将读取器对象的可迭代对象的下一行解析为列表,并根据当前方言进行解析。

csv_data = csv.reader(open('sample.csv'))
csv_data.next() # skip first row
for row in csv_data:
    print(row) # should print second row

Python 3.x

csvreader.__next__()

将可迭代对象中的下一行作为列表(如果该对象是从`reader()`返回的)或字典(如果它是`DictReader`实例),根据当前方言进行解析。通常应该调用此方法作为`next(reader)`。

csv_data = csv.reader(open('sample.csv'))
csv_data.__next__() # skip first row
for row in csv_data:
    print(row) # should print second row

1
文档中说:“通常应该调用next(reader)。” https://docs.python.org/3/library/csv.html#csv.csvreader.__next__ - jrc

4
这可能是一个非常古老的问题,但是使用 pandas 我们有一个非常简单的解决方案。
import pandas as pd

data=pd.read_csv('all16.csv',skiprows=1)
data['column'].min()

使用skiprows=1参数,我们可以跳过第一行,然后通过data['column'].min()找到最小值。


3
Python 3 CSV模块的文档提供了以下示例:
with open('example.csv', newline='') as csvfile:
    dialect = csv.Sniffer().sniff(csvfile.read(1024))
    csvfile.seek(0)
    reader = csv.reader(csvfile, dialect)
    # ... process CSV file contents here ...

Sniffer会尝试自动检测CSV文件的许多内容。您需要明确调用其has_header()方法来确定文件是否有标题行。如果有,则在迭代CSV行时跳过第一行。您可以像这样实现:

if sniffer.has_header():
    for header_row in reader:
        break
for data_row in reader:
    # do something with the row

2

因为这与我的工作有关,所以我会在这里分享。

如果我们不确定是否有标题,也不想导入嗅探器和其他东西怎么办?

如果您的任务很基础,例如打印或将内容添加到列表或数组中,您可以使用if语句:

# Let's say there's 4 columns
with open('file.csv') as csvfile:
     csvreader = csv.reader(csvfile)
# read first line
     first_line = next(csvreader)
# My headers were just text. You can use any suitable conditional here
     if len(first_line) == 4:
          array.append(first_line)
# Now we'll just iterate over everything else as usual:
     for row in csvreader:
          array.append(row)

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