Gấu trúc có thể tự động nhận ra ngày?


151

Hôm nay tôi rất ngạc nhiên bởi thực tế là trong khi đọc dữ liệu từ tệp dữ liệu (ví dụ) gấu trúc có thể nhận ra các loại giá trị:

df = pandas.read_csv('test.dat', delimiter=r"\s+", names=['col1','col2','col3'])

Ví dụ, nó có thể được kiểm tra theo cách này:

for i, r in df.iterrows():
    print type(r['col1']), type(r['col2']), type(r['col3'])

Trong số nguyên cụ thể, số float và chuỗi được nhận dạng chính xác. Tuy nhiên, tôi có một cột có ngày ở định dạng sau : 2013-6-4. Những ngày này được công nhận là chuỗi (không phải là đối tượng ngày python). Có cách nào để "học" gấu trúc đến ngày được công nhận không?


Vui lòng luôn nêu phiên bản gấu trúc, cho loại câu hỏi phụ thuộc phiên bản này. Vào tháng 7 năm 2013, đây sẽ là v0.11
smci

Và các kiểu chữ được cố định cho mỗi cột, bạn không cần phải lặp đi lặp lại df.iterrows()và xem chúng cho mỗi hàng, chỉ cần thực hiện df.info()một lần.
smci

Câu trả lời:


326

Bạn nên thêm parse_dates=True, hoặc parse_dates=['column name']khi đọc, điều đó thường đủ để phân tích nó một cách kỳ diệu. Nhưng luôn có những định dạng kỳ lạ cần được xác định bằng tay. Trong trường hợp như vậy, bạn cũng có thể thêm chức năng phân tích cú pháp ngày, đây là cách linh hoạt nhất có thể.

Giả sử bạn có một cột 'datetime' với chuỗi của mình, sau đó:

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)

Bằng cách này, bạn thậm chí có thể kết hợp nhiều cột thành một cột thời gian duy nhất, điều này hợp nhất một cột 'ngày' và 'thời gian' thành một cột 'datetime' duy nhất:

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)

Bạn có thể tìm thấy các chỉ thị (tức là các chữ cái được sử dụng cho các định dạng khác nhau) cho strptimestrftime trong trang này .


8
Không làm việc cho tôi, tôi đã nhận được lỗi sau:TypeError: strptime() argument 1 must be str, not float
Jean Paul

6
Tôi đã gặp lỗi này vì có nan trong khung dữ liệu của tôi.
Jean Paul

bạn có thể thêm một mục mà NaTs là vật liệu không phân tích được hoặc NaN hoặc / Ns không. vì có vẻ như trình phân tích cú pháp này hoàn toàn bỏ qua toàn bộ cột nếu có bất cứ thứ gì tương tự
Amir

Có một tùy chọn infer_datetime_format: "gấu trúc sẽ cố gắng suy ra định dạng của chuỗi thời gian trong các cột". Điều này có thể được sử dụng thay vì date_parser.
Winand

1
Lưu ý rằng nếu ngày của bạn ở ISO 8601định dạng, bạn không nên vượt qua infer_datetime_formathoặc chức năng phân tích cú pháp - nó chậm hơn nhiều so với việc để gấu trúc xử lý nó (đặc biệt là sau này). Định dạng ngày trong câu trả lời này cũng thuộc loại này
Mr_and_Mrs_D

20

Có lẽ giao diện gấu trúc đã thay đổi kể từ khi @Rutger trả lời, nhưng trong phiên bản tôi đang sử dụng (0.15.2), date_parserhàm nhận được danh sách ngày thay vì một giá trị. Trong trường hợp này, mã của anh ta nên được cập nhật như vậy:

dateparse = lambda dates: [pd.datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in dates]

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)

11

phương pháp pandas read_csv là tuyệt vời để phân tích ngày. Hoàn thành tài liệu tại http://pandas.pydata.org/pandas-docs/urdy/generated/pandas.io.parsers.read_csv.html

bạn thậm chí có thể có các phần ngày khác nhau trong các cột khác nhau và truyền tham số:

parse_dates : boolean, list of ints or names, list of lists, or dict
If True -> try parsing the index. If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a
separate date column. If [[1, 3]] -> combine columns 1 and 3 and parse as a single date
column. {‘foo : [1, 3]} -> parse columns 1, 3 as date and call result foo

Cảm biến mặc định của ngày hoạt động rất tốt, nhưng dường như nó thiên về các định dạng Ngày của người Bắc Mỹ. Nếu bạn sống ở nơi khác, đôi khi bạn có thể bị bắt bởi kết quả. Theo như tôi có thể nhớ 1/6/2000 có nghĩa là ngày 6 tháng 1 ở Hoa Kỳ trái ngược với ngày 1 tháng 6 nơi tôi sống. Nó đủ thông minh để xoay chúng xung quanh nếu ngày như 23/6/2000 được sử dụng. Có lẽ an toàn hơn để ở với các biến thể của ngày YYYYMMDD. Xin lỗi các nhà phát triển gấu trúc, ở đây nhưng tôi đã không kiểm tra nó với ngày địa phương gần đây.

bạn có thể sử dụng tham số date_parser để truyền một hàm để chuyển đổi định dạng của mình.

date_parser : function
Function to use for converting a sequence of string columns to an array of datetime
instances. The default uses dateutil.parser.parser to do the conversion.

2
Bạn có thể chỉ định dayfirstlà True cho ngày châu Âu / quốc tế. pandas.pydata.org/pandas-docs/urdy/generated/ từ
Will Gordon

10

Bạn có thể sử dụng pandas.to_datetime()theo khuyến nghị trong tài liệu cho pandas.read_csv():

Nếu một cột hoặc chỉ mục chứa một ngày không thể thay đổi, toàn bộ cột hoặc chỉ mục sẽ được trả về không thay đổi dưới dạng một kiểu dữ liệu đối tượng. Để phân tích cú pháp datetime không chuẩn, sử dụng pd.to_datetimesau pd.read_csv.

Bản giới thiệu:

>>> D = {'date': '2013-6-4'}
>>> df = pd.DataFrame(D, index=[0])
>>> df
       date
0  2013-6-4
>>> df.dtypes
date    object
dtype: object
>>> df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d')
>>> df
        date
0 2013-06-04
>>> df.dtypes
date    datetime64[ns]
dtype: object

nó cũng đang chuyển đổi các cột khác thành ngày, thuộc loại đối tượng
10:30

10

Khi hợp nhất hai cột thành một cột thời gian duy nhất, câu trả lời được chấp nhận sẽ tạo ra lỗi (phiên bản gấu trúc 0.20.3), do các cột được gửi riêng cho hàm date_parser.

Các công việc sau đây:

def dateparse(d,t):
    dt = d + " " + t
    return pd.datetime.strptime(dt, '%d/%m/%Y %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)

1
Tôi đang sử dụng gấu trúc 0,22 và đồng ý rằng câu trả lời được chấp nhận không còn hoạt động.
Đại

Điều này tạo ra một "TypeError: chỉ có thể ghép str (không phải" float ") thành str" cho tôi. Cột ngày là d / m / y và cột thời gian là H: M: 00
IceQueeny

8

Có - theo pandas.read_csv tài liệu :

Lưu ý: Đường dẫn nhanh tồn tại cho các ngày có định dạng iso8601 .

Vì vậy, nếu csv của bạn có một cột được đặt tên datetime2013-01-01T01:01ví dụ như ngày tháng , việc chạy này sẽ khiến gấu trúc (tôi trên v0.19.2) tự động lấy ngày và giờ:

df = pd.read_csv('test.csv', parse_dates=['datetime'])

Lưu ý rằng bạn cần phải vượt qua một cách rõ ràng parse_dates, nó không hoạt động mà không có.

Xác minh với:

df.dtypes

Bạn sẽ thấy kiểu dữ liệu của cột là datetime64[ns]


Tôi nghĩ rằng bạn hiểu sai câu hỏi. Người dùng tò mò liệu tùy chọn có thể được kích hoạt cho định dạng chuỗi của mình hay không.
Arya McCarthy

@AryaMcCarthy umm, về cơ bản anh ấy muốn ngày được nhận dạng chính xác, vì vậy tôi đang đề cập đến cách anh ấy có thể chuyển đổi dữ liệu nguồn để nó được gấu trúc nhận ra một cách tự nhiên. Không nơi nào anh ta đề cập đến anh ta không thể thay đổi định dạng của dữ liệu nguồn.
Gaurav

1

Nếu hiệu suất quan trọng với bạn, hãy chắc chắn rằng bạn có thời gian:

import sys
import timeit
import pandas as pd

print('Python %s on %s' % (sys.version, sys.platform))
print('Pandas version %s' % pd.__version__)

repeat = 3
numbers = 100

def time(statement, _setup=None):
    print (min(
        timeit.Timer(statement, setup=_setup or setup).repeat(
            repeat, numbers)))

print("Format %m/%d/%y")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,07/29/15
x2,07/29/15
x3,07/29/15
x4,07/30/15
x5,07/29/15
x6,07/29/15
x7,07/29/15
y7,08/05/15
x8,08/05/15
z3,08/05/15
''' * 100)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%m/%d/%y")); data.seek(0)')

print("Format %Y-%m-%d %H:%M:%S")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,2016-10-15 00:00:43
x2,2016-10-15 00:00:56
x3,2016-10-15 00:00:56
x4,2016-10-15 00:00:12
x5,2016-10-15 00:00:34
x6,2016-10-15 00:00:55
x7,2016-10-15 00:00:06
y7,2016-10-15 00:00:01
x8,2016-10-15 00:00:00
z3,2016-10-15 00:00:02
''' * 1000)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")); data.seek(0)')

in:

Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28) 
[Clang 6.0 (clang-600.0.57)] on darwin
Pandas version 0.23.4
Format %m/%d/%y
0.19123052499999993
8.20691274
8.143124389
1.2384357139999977
Format %Y-%m-%d %H:%M:%S
0.5238807110000039
0.9202787830000005
0.9832778819999959
12.002349824999996

Vì vậy, với ngày được định dạng iso8601 ( %Y-%m-%d %H:%M:%Srõ ràng là ngày có định dạng iso8601, tôi đoán rằng T có thể được bỏ và thay thế bằng khoảng trắng ), bạn không nên chỉ định infer_datetime_format(không tạo ra sự khác biệt với những ngày phổ biến hơn) trình phân tích cú pháp chỉ trong hiệu suất làm tê liệt. Mặt khác, date_parserkhông tạo ra sự khác biệt với các định dạng ngày không chuẩn. Hãy chắc chắn thời gian trước khi bạn tối ưu hóa, như bình thường.


1

Trong khi tải tệp csv chứa cột ngày. Chúng tôi có hai cách tiếp cận để tạo gấu trúc để nhận ra cột ngày tức là

  1. Gấu trúc rõ ràng nhận ra định dạng bằng arg date_parser=mydateparser

  2. Gấu trúc ngầm nhận ra định dạng của agr infer_datetime_format=True

Một số dữ liệu cột ngày

01/01/18

01/02/18

Ở đây chúng ta không biết hai điều đầu tiên Có thể là tháng hoặc ngày. Vì vậy, trong trường hợp này, chúng ta phải sử dụng Phương pháp 1: - Rõ ràng vượt qua định dạng

    mydateparser = lambda x: pd.datetime.strptime(x, "%m/%d/%y")
    df = pd.read_csv(file_name, parse_dates=['date_col_name'],
date_parser=mydateparser)

Phương pháp 2: - Ẩn hoặc Tự động nhận dạng

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.