จะเพิกเฉยต่อข้อมูลบรรทัดแรกเมื่อประมวลผลข้อมูล CSV ได้อย่างไร


113

ฉันขอให้ 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

คุณช่วยอธิบายได้ไหมว่าคุณกำลังทำอะไรไม่ใช่แค่ให้รหัส ฉันยังใหม่มากกับ Python และต้องการแน่ใจว่าฉันเข้าใจทุกอย่าง


5
คุณทราบหรือไม่ว่าคุณกำลังสร้างตัวสร้างที่ส่งคืนค่า1.0สำหรับแต่ละบรรทัดในไฟล์ของคุณจากนั้นจึงใช้ค่าต่ำสุดซึ่งจะเป็น1.0?
Wooble

@ Wooble ในทางเทคนิคมันเป็นเครื่องกำเนิดไฟฟ้าขนาดใหญ่ของ1.0. :)
Dougal

@Wooble good catch - ... datatype(row[column]... คือสิ่งที่ฉันเดาว่า OP พยายามบรรลุแม้ว่า
Jon Clements

ฉันมีคนเขียนรหัสนั้นให้ฉันและไม่ได้จับมันขอบคุณฮ่าฮ่า!

คำตอบ:


106

คุณสามารถใช้อินสแตนซ์ของคลาส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)

เนื่องจากdatatypeและcolumnมีการเข้ารหัสในตัวอย่างของคุณการประมวลผล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" ในเอกสารดังนั้นฉันคิดว่าเป็นวิธีที่กำหนดให้ทำ ผมยอมรับว่าทำมันอยู่บนพื้นฐานของหนึ่งบรรทัดของข้อมูลที่ไม่ได้ดูเหมือนมันก็จะมีข้อมูลมากพอที่จะทำเช่นการตัดสินใจ แต่ผมไม่มีความคิดตั้งแต่วิธีSnifferงานไม่ได้อธิบาย FWIW ฉันไม่เคยเห็นว่าhas_header(file.readline())มีการใช้งานและแม้ว่าจะใช้งานได้เกือบตลอดเวลา แต่ฉันก็คงสงสัยในแนวทางนี้อย่างมากด้วยเหตุผลที่ระบุไว้
martineau

ขอบคุณสำหรับข้อมูลของคุณ อย่างไรก็ตามดูเหมือนว่าการใช้file.read(1024) สร้างข้อผิดพลาดใน csv lib ของ python : ดูตัวอย่างเช่นที่นี่
Anto

@Anto: ฉันไม่เคยพบข้อผิดพลาดเช่นนี้มาก่อนเลย - 1024 ไบต์ไม่ใช่หน่วยความจำมากนัก - และไม่ได้เป็นปัญหาสำหรับคนอื่น ๆ อีกมากมายจากการโหวตที่ได้รับคำตอบนี้ (เช่นเดียวกับ ของผู้ที่อ่านและปฏิบัติตามเอกสารประกอบ) ด้วยเหตุผลเหล่านี้ฉันสงสัยอย่างยิ่งว่ามีอย่างอื่นที่ทำให้คุณเกิดปัญหา
martineau

ฉันวิ่งเข้าไปในข้อผิดพลาดเดียวกันนี้แน่นอนเร็วที่สุดเท่าที่ผมเปลี่ยนจากการreadline() read(1024)จนถึงตอนนี้ฉันหาคนที่เปลี่ยนมาใช้ readline เพื่อแก้ปัญหา csv.dialect ได้เท่านั้น
Anto

75

หากต้องการข้ามบรรทัดแรกเพียงโทร:

next(inf)

ไฟล์ใน Python เป็นตัวทำซ้ำในบรรทัด


22

ในกรณีการใช้งานที่คล้ายกันฉันต้องข้ามบรรทัดที่น่ารำคาญก่อนบรรทัดที่มีชื่อคอลัมน์จริงของฉัน วิธีนี้ใช้ได้ผลดี 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! นั่นดูมีประสิทธิภาพมากแน่นอน ฉันโพสต์คำตอบของฉันเนื่องจากคำตอบที่ได้รับการยอมรับไม่ได้ผลสำหรับฉัน (ตอนนี้จำเหตุผลไม่ได้) อะไรคือปัญหาในการกำหนด data = dict () แล้วกรอกข้อมูลทันที (เมื่อเทียบกับคำแนะนำของคุณ)
Maarten

1
ไม่ผิดที่จะทำdata = dict()และกรอกข้อมูล แต่มันไม่มีประสิทธิภาพและไม่ใช่สำนวน นอกจากนี้ควรใช้ตัวอักษรตามคำบอก ( {}) และenumerateถึงแม้ว่า
Veedrac

1
FWIW คุณควรตอบกลับโพสต์ของฉัน@Veedracหากคุณต้องการให้แน่ใจว่าฉันได้รับแจ้งแม้ว่า Stack Overflow ดูเหมือนจะเดาได้จากชื่อผู้ใช้ (ฉันไม่ได้เขียน@Maartenเพราะผู้ตอบจะได้รับแจ้งตามค่าเริ่มต้น)
Veedrac


19

โดยปกติคุณจะใช้next(incsv)ซึ่งเลื่อนตัววนซ้ำหนึ่งแถวดังนั้นคุณจึงข้ามส่วนหัวไป อีกอัน (บอกว่าคุณต้องการข้าม 30 แถว) จะเป็น:

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

6

ใช้ csv.DictReader แทน csv.Reader หากไม่ใส่พารามิเตอร์ชื่อฟิลด์ระบบจะใช้ค่าในแถวแรกของไฟล์ csv เป็นชื่อฟิลด์ จากนั้นคุณจะสามารถเข้าถึงค่าฟิลด์โดยใช้ row ["1"] เป็นต้น


2

แพ็กเกจ 'แพนด้า' ใหม่อาจมีความเกี่ยวข้องมากกว่า 'csv' โค้ดด้านล่างจะอ่านไฟล์ CSV โดยค่าเริ่มต้นจะตีความบรรทัดแรกเป็นส่วนหัวของคอลัมน์และค้นหาค่าต่ำสุดในคอลัมน์

import pandas as pd

data = pd.read_csv('all16.csv')
data.min()

และคุณสามารถเขียนเป็นบรรทัดเดียวด้วย:pd.read_csv('all16.csv').min()
Finn Årup Nielsen

1

ห้องสมุดกระดาษห่อขนาดเล็กของฉันก็ทำงานได้ดีเช่นกัน

>>> import pyexcel as pe
>>> data = pe.load('all16.csv', name_columns_by_row=0)
>>> min(data.column[1])

ในขณะเดียวกันหากคุณทราบว่าดัชนีของคอลัมน์ส่วนหัวคืออะไรเช่น "คอลัมน์ 1" คุณสามารถดำเนินการนี้แทนได้:

>>> min(data.column["Column 1"])

1

สำหรับฉันวิธีที่ง่ายที่สุดคือใช้ range

import csv

with open('files/filename.csv') as I:
    reader = csv.reader(I)
    fulllist = list(reader)

# Starting with data skipping header
for item in range(1, len(fulllist)): 
    # Print each row using "item" as the index value
    print (fulllist[item])  

1

เนื่องจากสิ่งนี้เกี่ยวข้องกับสิ่งที่ฉันกำลังทำฉันจะแบ่งปันที่นี่

จะเกิดอะไรขึ้นถ้าเราไม่แน่ใจว่ามีส่วนหัวและคุณไม่รู้สึกอยากนำเข้า sniffer และสิ่งอื่น ๆ ?

หากงานของคุณเป็นพื้นฐานเช่นการพิมพ์หรือต่อท้ายรายการหรืออาร์เรย์คุณสามารถใช้คำสั่ง 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)

1

เอกสารสำหรับโมดูลหลาม 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



0

Python 3.X

จัดการ UTF8 BOM + HEADER

มันค่อนข้างน่าผิดหวังที่csvโมดูลไม่สามารถรับส่วนหัวได้อย่างง่ายดายนอกจากนี้ยังมีข้อผิดพลาดกับ UTF-8 BOM (ถ่านตัวแรกในไฟล์) สิ่งนี้ใช้ได้กับฉันโดยใช้เฉพาะcsvโมดูล:

import csv

def read_csv(self, csv_path, delimiter):
    with open(csv_path, newline='', encoding='utf-8') as f:
        # https://bugs.python.org/issue7185
        # Remove UTF8 BOM.
        txt = f.read()[1:]

    # Remove header line.
    header = txt.splitlines()[:1]
    lines = txt.splitlines()[1:]

    # Convert to list.
    csv_rows = list(csv.reader(lines, delimiter=delimiter))

    for row in csv_rows:
        value = row[INDEX_HERE]

0

ฉันจะแปลง csvreader เป็นรายการจากนั้นเปิดองค์ประกอบแรก

import csv        

with open(fileName, 'r') as csvfile:
        csvreader = csv.reader(csvfile)
        data = list(csvreader)               # Convert to list
        data.pop(0)                          # Removes the first row

        for row in data:
            print(row)

0

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 ()) หรือ dict (ถ้าเป็นอินสแตนซ์ DictReader) โดยแยกวิเคราะห์ตามภาษาถิ่นปัจจุบัน โดยปกติคุณควรเรียกสิ่งนี้ว่า 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.