25/09/2018, 22:27

Một số tip khi sử dụng python pandas bạn nên biết.

Pandas là một thư viện cơ bản cho phân tích, xử lý dữ liệu và khoa học dữ liệu. Trong bài viết này sẽ cung cấp một số mẹo hữu ích giúp việc đọc dữ liệu trở lên dễ dàng, nhanh chóng và linh hoạt hơn. Nào ta cũng bắt đầu. Configure Options & Settings at Interpreter Startup Pandas có một trình ...

Pandas là một thư viện cơ bản cho phân tích, xử lý dữ liệu và khoa học dữ liệu. Trong bài viết này sẽ cung cấp một số mẹo hữu ích giúp việc đọc dữ liệu trở lên dễ dàng, nhanh chóng và linh hoạt hơn. Nào ta cũng bắt đầu.

Configure Options & Settings at Interpreter Startup

Pandas có một trình tiết kiệm năng suất rất lớn để thiết lập và tùy chọn khi khởi động trình phiên dịch. Bạn có thể dử dụng pd.set_option() để định cấu hình cho nội dung chính bằng tệp khởi động python hoặc IPython.

import pandas as pd

def start():
    options = {
        'display': {
            'max_columns': None,
            'max_colawidth': 25,
            'expand_frame_repr': False,  # Don't wrap to multiple pages
            'max_rows': 14,
            'max_seq_items': 50,         # Max length of printed sequence
            'precision': 4,
            'show_dimensions': False
        },
        'mode': {
            'chained_assignment': None   # Controls SettingWithCopyWarning
        }
    }

    for category, option in options.items():
        for op, value in option.items():
            pd.set_option(f'{category}.{op}', value)  # Python 3.6+

if __name__ == '__main__':
    start()
    del start  # Clean up namespace in the interpreter

Nếu bạn khởi chạy trình phiên dịch, bạn sẽ thấy mọi thứ trong tập lệnh khởi động đã được thực thi và Pandas được nhập tự động với bộ tùy chọn của bạn:

>>> pd.__name__
'pandas'
>>> pd.get_option('display.max_rows')
14

Một ví dụ khi bạn làm việc với tập abalonebạn sẽ thấy dữ liệu sẽ bị cắt ngắn tại hàng 14 với 4 ký tự dạng floats:

>>> url = ('https://archive.ics.uci.edu/ml/'
...        'machine-learning-databases/abalone/abalone.data')
>>> cols = ['sex', 'length', 'diam', 'height', 'weight', 'rings']
>>> abalone = pd.read_csv(url, usecols=[0, 1, 2, 3, 4, 8], names=cols)

>>> abalone
     sex  length   diam  height  weight  rings
0      M   0.455  0.365   0.095  0.5140     15
1      M   0.350  0.265   0.090  0.2255      7
2      F   0.530  0.420   0.135  0.6770      9
3      M   0.440  0.365   0.125  0.5160     10
4      I   0.330  0.255   0.080  0.2050      7
5      I   0.425  0.300   0.095  0.3515      8
6      F   0.530  0.415   0.150  0.7775     20
...   ..     ...    ...     ...     ...    ...
4170   M   0.550  0.430   0.130  0.8395     10
4171   M   0.560  0.430   0.155  0.8675      8
4172   F   0.565  0.450   0.165  0.8870     11
4173   M   0.590  0.440   0.135  0.9660     10
4174   M   0.600  0.475   0.205  1.1760      9
4175   F   0.625  0.485   0.150  1.0945     10
4176   M   0.710  0.555   0.195  1.9485     12

Make Toy Data Structures With Pandas’ Testing Module

Cách thức ẩn trong module thử nghiệm của Pandas là một số chức năng tiện lợi để nhanh chóng xây dựng các Chuỗi chuẩn và DataFrames bán thực tế:

>>> import pandas.util.testing as tm
>>> tm.N, tm.K = 15, 3  # Module-level default rows/columns

>>> import numpy as np
>>> np.random.seed(444)

>>> tm.makeTimeDataFrame(freq='M').head()
                 A       B       C
2000-01-31  0.3574 -0.8804  0.2669
2000-02-29  0.3775  0.1526 -0.4803
2000-03-31  1.3823  0.2503  0.3008
2000-04-30  1.1755  0.0785 -0.1791
2000-05-31 -0.9393 -0.9039  1.1837

>>> tm.makeDataFrame().head()
                 A       B       C
nTLGGTiRHF -0.6228  0.6459  0.1251
WPBRn9jtsR -0.3187 -0.8091  1.1501
7B3wWfvuDA -1.9872 -1.0795  0.2987
yJ0BTjehH1  0.8802  0.7403 -1.2154
0luaYUYvy1 -0.9320  1.2912 -0.2907

Có tất cả là 30 options để bạn sử dụng. bạn có thể xem danh sách đây đủ các lệnh này bằng cách gọi hàm dir()

>>> [i for i in dir(tm) if i.startswith('make')]
['makeBoolIndex',
 'makeCategoricalIndex',
 'makeCustomDataframe',
 'makeCustomIndex',
 # ...,
 'makeTimeSeries',
 'makeTimedeltaIndex',
 'makeUIntIndex',
 'makeUnicodeIndex']

Những hàm này có thể sẽ hữu ích cho việc đo điểm chuẩn, xác nhận thử nghiệm và thứ nghiệm với các phương thức pandas hiếm gặp.

Tận dụng các phương pháp Accessor

Có thể bạn đã nghe nói về các accessor, nó hơi giống như một getter (mặc dù getters và setters được sử dụng không thường xuyên trong Python). Bạn có thể liên tưởng đến một người truy cập Pandas và được phục vụ như một giao diện cho các phương thức bổ sung.

Pandas Series có 3 accessors là 'cat', 'str', 'dt'

>>> pd.Series._accessors
{'cat', 'str', 'dt'}

.cat là dữ liệu phân loại, .str là dự liệu chuỗi và .dt là dữ liệu dạng datetime. Chúng ta thử làm việc với str. giả sử bạn có dữ liệu raw dạng city/state/ZIP dưới dạng single field trong Pandas Series.

Ta cần phải vector hóa các chuỗi pandas này, điều này nghĩa là chúng hoạt động hoàn toàn trên mảng mà ko hề có một vòng lặp rõ ràng nào:

>>> addr = pd.Series([
...     'Washington, D.C. 20003',
...     'Brooklyn, NY 11211-1755',
...     'Omaha, NE 68154',
...     'Pittsburgh, PA 15211'
... ])

>>> addr.str.upper()
0     WASHINGTON, D.C. 20003
1    BROOKLYN, NY 11211-1755
2            OMAHA, NE 68154
3       PITTSBURGH, PA 15211
dtype: object

>>> addr.str.count(r'd')  # 5 or 9-digit zip?
0    5
1    9
2    5
3    5
dtype: int64

Ví dụ bạn muốn tách riêng các phần city/state/ZIP thành các trường DataFrame. Bạn có thể dùng biểu thức chính quy .str.extract () để "trích xuất" các phần của mỗi ô trong Series. Trong .str.extract(), .str là accessor, và .str.extract () là một phương thức accessor:

>>> regex = (r'(?P<city>[A-Za-z ]+), '      # One or more letters
...          r'(?P<state>[A-Z]{2}) '        # 2 capital letters
...          r'(?P<zip>d{5}(?:-d{4})?)')  # Optional 4-digit extension
...
>>> addr.str.replace('.', ').str.extract(regex)
         city state         zip
0  Washington    DC       20003
1    Brooklyn    NY  11211-1755
2       Omaha    NE       68154
3  Pittsburgh    PA       15211

Thật hữu ích khi biết một chút về cách các phương thức truy cập này hoạt động như một lý do thúc đẩy vì sao bạn nên sử dụng chúng ngay từ đầu, thay vì một cái gì đó như addr.apply (re.findall, ...).

Mỗi accessor chính nó là một python class:

  • .str maps to StringMethods.
  • .dt maps to CombinedDatetimelikeProperties.
  • .cat routes to CategoricalAccessor.

Các lớp độc lập này sau đó được “gắn” vào lớp Series bằng cách sử dụng một CachedAccessor. Đó là khi chúng được bao bọc trong CachedAccessor.

CachedAccessor được lấy cảm hứng từ một thiết kế "cached property": một thuộc tính chỉ được tính một lần cho mỗi cá thể và sau đó được thay thế bằng một thuộc tính thông thường. Nó thực hiện điều này bằng cách nạp chồng phương thức .__ get __ (), là một phần của "Python’s descriptor protocol".

Accessor thứ hai là .dt, là dữ liệu giống như datetime. Về mặt kỹ thuật, nó thuộc về DateTimeIndex của Pandas, và nếu được gọi trên một Series, nó được chuyển đổi thành một DatetimeIndex trước:

>>> daterng = pd.Series(pd.date_range('2017', periods=9, freq='Q'))
>>> daterng
0   2017-03-31
1   2017-06-30
2   2017-09-30
3   2017-12-31
4   2018-03-31
5   2018-06-30
6   2018-09-30
7   2018-12-31
8   2019-03-31
dtype: datetime64[ns]

>>>  daterng.dt.day_name()
0      Friday
1      Friday
2    Saturday
3      Sunday
4    Saturday
5    Saturday
6      Sunday
7      Monday
8      Sunday
dtype: object

>>> # Second-half of year only
>>> daterng[daterng.dt.quarter > 2]
2   2017-09-30
3   2017-12-31
6   2018-09-30
7   2018-12-31
dtype: datetime64[ns]

>>> daterng[daterng.dt.is_year_end]
3   2017-12-31
7   2018-12-31
dtype: datetime64[ns]

Accessor thứ 3 là .cat chỉ dành cho dữ liệu Phân loại, mà bạn sẽ thấy ngay trong phần riêng của nó.

Create a DatetimeIndex From Component Columns

Nói về dữ liệu datetime, ta hoàn toàn có thể toạn Pandas DatetimeIndex từ nhiều cột thành phần cùng nhau tạo thành một ngày hoặc ngày giờ.

>>> from itertools import product
>>> datecols = ['year', 'month', 'day']

>>> df = pd.DataFrame(list(product([2017, 2016], [1, 2], [1, 2, 3])),
...                   columns=datecols)
>>> df['data'] = np.random.randn(len(df))
>>> df
    year  month  day    data
0   2017      1    1 -0.0767
1   2017      1    2 -1.2798
2   2017      1    3  0.4032
3   2017      2    1  1.2377
4   2017      2    2 -0.2060
5   2017      2    3  0.6187
6   2016      1    1  2.3786
7   2016      1    2 -0.4730
8   2016      1    3 -2.1505
9   2016      2    1 -0.6340
10  2016      2    2  0.7964
11  2016      2    3  0.0005

>>> df.index = pd.to_datetime(df[datecols])
>>> df.head()
            year  month  day    data
2017-01-01  2017      1    1 -0.0767
2017-01-02  2017      1    2 -1.2798
2017-01-03  2017      1    3  0.4032
2017-02-01  2017      2    1  1.2377
2017-02-02  2017      2    2 -0.2060

Cuối cùng, bạn có thể drop các cột riêng lẻ cũ và chuyển đổi thành một Chuỗi:

>>> df = df.drop(datecols, axis=1).squeeze()
>>> df.head()
2017-01-01   -0.0767
2017-01-02   -1.2798
2017-01-03    0.4032
2017-02-01    1.2377
2017-02-02   -0.2060
Name: data, dtype: float64

>>> df.index.dtype_str
'datetime64[ns]

Đằng sau việc truyền một DataFrame là một DataFrame giống như một từ điển Python, nơi các tên cột là các khóa và các cột riêng lẻ (Series) là các giá trị từ điển. Đó là lý do tại sao pd.to_datetime (df [datecols] .to_dict (orient = 'list')) cũng sẽ hoạt động trong trường hợp này. Điều này phản ánh việc xây dựng datetime.datetime của Python, trong đó bạn chuyển các đối số từ khóa như datetime.datetime (năm = 2000, tháng = 1, ngày = 15, giờ = 10).

0