2010-04-19 30 views
9

Tôi đã có tập tin với một định dạng mà trông như thế này một CSV:file Reading CSV trong NumPy nơi delimiter là ""

"FieldName1", "FieldName2", "FieldName3", "FieldName4"
"04/13/2010 14: 45: 07.008", "7.59484916392", "10", "6.552373"
"04/13/2010 14: 45: 22.010", "6.55478493312", "9", " 3.5378543 "
...

Lưu ý rằng có các ký tự trích dẫn kép ở đầu và cuối mỗi dòng trong t tệp CSV và chuỗi "," được sử dụng để phân tách các trường trong mỗi dòng. Số lượng trường trong tệp CSV có thể thay đổi từ tệp này sang tệp khác.

Khi tôi cố gắng đọc này vào numpy qua:
import numpy as np
data = np.genfromtxt(csvfile, dtype=None, delimiter=',', names=True)
tất cả các dữ liệu được đọc trong khi giá trị chuỗi, bao quanh bởi ký tự ngoặc kép. Không hợp lý, nhưng không sử dụng nhiều đối với tôi như tôi sau đó phải quay trở lại và chuyển đổi tất cả các cột để đúng kiểu của nó

Khi tôi sử dụng delimiter='","' thay vào đó, mọi thứ hoạt động như tôi muốn, trừ cho 1 và cuối cùng lĩnh vực. Khi bắt đầu dòng và ký tự kết thúc của dòng là một ký tự trích dẫn kép duy nhất, ký tự này không được xem là dấu phân cách hợp lệ cho trường đầu tiên và cuối cùng, vì vậy chúng được đọc như ví dụ: "04/13/2010 14:45:07.0086.552373" - lưu ý các ký tự ngoặc kép hàng đầu và cuối cùng tương ứng. Bởi vì các ký tự dư thừa này, giả định rằng các trường đầu tiên và cuối cùng là cả hai kiểu String; Tôi không muốn đó là trường hợp

Có cách nào hướng dẫn đọc sách trong các tệp được định dạng theo cách này mà tôi muốn, mà không cần phải quay lại và "sửa" cấu trúc của mảng bị sần sau lần đọc đầu tiên?

Trả lời

12

Vấn đề cơ bản là NumPy không hiểu khái niệm về dấu ngoặc kép (trong khi mô-đun csv không). Khi bạn nói delimiter='","', bạn đang nói với NumPy rằng dấu phân tách cột theo nghĩa đen là dấu phẩy được trích dẫn, nghĩa là dấu ngoặc kép nằm xung quanh dấu phẩy, chứ không phải giá trị, vì vậy các dấu ngoặc kép bạn nhận được trên cột đầu tiên và cột cuối cùng được mong đợi.

Nhìn vào các tài liệu chức năng, tôi nghĩ rằng bạn sẽ cần phải đặt converters tham số để dải dấu ngoặc kép cho bạn (mặc định không):

import re 
import numpy as np 

fieldFilter = re.compile(r'^"?([^"]*)"?$') 
def filterTheField(s): 
    m = fieldFilter.match(s.strip()) 
    if m: 
     return float(m.group(1)) 
    else: 
     return 0.0 # or whatever default 

#... 

# Yes, sorry, you have to know the number of columns, since the NumPy docs 
# don't say you can specify a default converter for all columns. 
convs = dict((col, filterTheField) for col in range(numColumns)) 
data = np.genfromtxt(csvfile, dtype=None, delimiter=',', names=True, 
    converters=convs) 

Hoặc bỏ np.genfromtxt() và để csv.csvreader cung cấp cho bạn các tập tin của nội dung một hàng tại một thời điểm, dưới dạng danh sách các chuỗi, sau đó bạn chỉ cần lặp qua các phần tử và tạo ma trận:

reader = csv.csvreader(csvfile) 
result = np.array([[float(col) for col in row] for row in reader]) 
# BTW, column headings are in reader.fieldnames at this point. 

EDIT: OK, có vẻ như tệp của bạn không phải là tất cả. Trong trường hợp đó, bạn có thể đặt convs khi cần thiết trong trường hợp genfromtxt, hoặc tạo ra một vector của các chức năng chuyển đổi trong trường hợp csv.csvreader:

reader = csv.csvreader(csvfile) 
converters = [datetime, float, int, float] 
result = np.array([[conv(col) for col, conv in zip(row, converters)] 
    for row in reader]) 
# BTW, column headings are in reader.fieldnames at this point. 

EDIT 2: Được rồi, cột biến đếm ... nguồn dữ liệu của bạn chỉ muốn làm cho cuộc sống trở nên khó khăn. May mắn thay, chúng tôi chỉ có thể sử dụng magic ...

reader = csv.csvreader(csvfile) 
result = np.array([[magic(col) for col in row] for row in reader]) 

... trong đó magic() chỉ là tên tôi đã rời khỏi đỉnh đầu của tôi để có chức năng. (! Psyche)

Tại tồi tệ nhất, nó có thể là một cái gì đó như:

def magic(s): 
    if '/' in s: 
     return datetime(s) 
    elif '.' in s: 
     return float(s) 
    else: 
     return int(s) 

lẽ NumPy có một chức năng mà phải mất một chuỗi và trả về một yếu tố duy nhất với đúng loại. numpy.fromstring() trông gần, nhưng nó có thể giải thích khoảng trống trong dấu thời gian của bạn dưới dạng dấu tách cột.

P.S. Một nhược điểm với csvreader Tôi thấy là nó không loại bỏ bình luận; real csv tệp không có nhận xét.

+1

Phương thức 'str.replace ('"', '') 'sẽ hoạt động nhanh hơn biểu thức chính quy nếu tệp đầu vào lớn (nhiều MB hoặc GB) và sẽ đúng nếu bạn có thể giả sử' " 'ký tự sẽ không xuất hiện ở giữa một trường, chỉ ở cuối. – gotgenes

+0

Cảm ơn Mike và gotgenes, nhưng tôi cũng nên đề cập rằng tệp CSV có số lượng cột thay đổi. Tôi có thể sử dụng cách tiếp cận bạn đã mô tả bằng cách thêm bước đầu tiên để đọc trong hồ sơ đầu tiên của tệp để xác định số lượng cột, sau đó sử dụng làm đầu vào cho các bước sau, nhưng có vẻ khá clunky. Có cách nào tốt hơn không? – monch1962

+0

Lưu ý nhỏ: bạn không cần phải sử dụng 're.compile()' vì chỉ sử dụng 're.match()' trực tiếp sẽ lưu lại biểu thức chính quy đã được biên dịch. – blokeley

Các vấn đề liên quan