24/03/2017 15:59 24/03/2017 15:59 890
Dùng Python để học thống kê

Dùng Python để học thống kê

Nguyễn Việt Hưng, Toán Tin K53
 
Đồ thị của một tập dữ liệu theo phân phối chuẩn
 
Statistics (thống kê) là một nhánh của toán học, thực hiện thu thập, phân tích, thấu hiểu, và biểu diễn một lượng số liệu lớn.
 

Là một cựu sinh viên viện Toán Ứng Dụng và Tin Học của đại học Bách Khoa Hà Nội, nhưng sau 4 năm không động tới thì tôi thậm chí còn chả nhớ nổi một khái niệm đã học ở trường, không phân biệt nổi phương sai và độ lệch chuẩn. Sau ngần ấy thời gian đi làm, tôi nhận ra thống kê là một bộ môn thực hành (chứ không phải lý thuyết) đầy thú vị. Ta lấy một đống dữ liệu, soi mói theo các góc cạnh khác nhau để tìm ra những “bí ẩn” trong đống dữ liệu đó. Đây cũng chính là nền tảng của ngành “data science" đang được xem ngành hot nhất hiện nay.

Tôi tự học thống kê vì muốn có khả năng thấu hiểu dữ liệu, sử dụng các công cụ lập trình vào để hiểu rõ ràng mọi khái niệm cần thiết, chứ không học vẹt như sinh viên để lấy điểm, cắm đầu vào tính tích phân, đạo hàm mà không biết để làm gì.

Loạt bài này tìm hiểu các khái niệm trong thống kê, học các khái niệm đó 
bằng tiếng Anh, dùng Python để lập trình các hàm toán học dùng trong tính toán thống kê (bạn không cần phải biết lập trình cũng vẫn hiểu được bài viết) và sử dụng các công cụ lập trình để “làm thống kê”. Hạn chế tối đa việc dùng các khái niệm toán học, các công thức tự dưng xuất hiện.

Thống kê là một nhánh của toán học, có tên tiếng Anh là statistics /stəˈtɪstɪks/. Ở trường học hay đưa khái niệm xác suất kèm với thống kê, nhưng ở đây tôi thấy không (chưa) cần thiết phải đưa xác suất vào.

Data /ˈdeɪtə/ — số nhiều của datum /ˈdeɪtəm/: dữ liệu. 
Ta sẽ dùng Python list để chứa data.

data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25, 100]

Data có thể là một tập hợp đầy đủ các giá trị cần xem xét (population /pɒpjʊˈleɪʃ(ə)n/ tập hợp), hoặc chỉ bao gồm một phần nhỏ trong bộ dữ liệu (sample /ˈsɑːmp(ə)l/ mẫu).

Khi sử dụng các hàm thống kê, ta sẽ thực hiện chúng trên 1 sample hoặc 1 population.

mean /miːn/

mean hay đầy đủ là arithmetic mean, là tổng đại số của tất cả các số trong data, chia cho số điểm dữ liệu (data point). Mean được ký hiệu bằng ký tự latin “muy”: μ

Xác suất thống kê tiếng Việt gọi đây là trung bình. Trong tiếng Anh, mean hay được gọi là the average (trung bình), mặc dù đây chỉ là một trong nhiều cách tính trung bình toán học khác.

Mean là một giá trị dùng để biểu diễn điểm trung tâm (central location) của data. Tính trên Python:

def mean(data):
return sum(data)/len(data)
mu = mean(data) # mu - đọc là muy, là tên tiếng Anh của chữ latin: μ
print(mu)
# 12.333333333333334

mean rất dễ bị “lệch” khi dữ liệu có những giá trị rất khác biệt so với các giá trị còn lại, ví dụ số 100 trong data ở trên là một giá trị rất khác. Bởi thế, nếu chỉ dùng mean để đưa ra “cảm nhận" về điểm trung tâm của bộ dữ liệu sẽ không được chính xác. Người ta đưa ra thêm khái niệm median để tính điểm trung tâm theo một cách khác, mà giá trị thu được sẽ biểu diễn điểm trung tâm một cách “tốt hơn”.

median /ˈmiːdɪən/

median — giá trị ở giữa (middle value)

Xác suất thống kê tiếng Việt gọi đây là trung vị.
Ta sắp xếp data theo chiều tăng dần, sau đó xác định giá trị ở giữa. Khi xác định giá trị ở giữa, xảy ra 2 trường hợp:
- số data point là chẵn: lấy 2 điểm ở giữa và lấy giá trị trung bình (cách làm này gọi là tính “mean of middle two”).
- số data point là lẻ: lấy luôn điểm ở giữa.

def median(data):
data = sorted(data)
n = len(data)
if n % 2 == 1:
return data[n//2]
else:
i = n//2
return (data[i - 1] + data[i])/2
median(data)
# 1.5

Rõ ràng, median (1.5) phản ánh điểm giữa của tập dữ liệu chính xác hơn so với mean (12.333333333333334).

median low và median high

median có thể là một giá trị không trùng với 1 data point cụ thể (trường hợp có chẵn data point), mà có lúc người ta lại muốn lấy một data point để làm điểm trung tâm của bộ dữ liệu. Median low là data point nhỏ hơn trong 2 điểm giữa, median high là data point lớn hơn trong 2 điểm ở giữa.

def median_low(data):
data = sorted(data)
n = len(data)
if n % 2 == 1:
return data[n//2]
else:
return data[n//2-1]
def median_high(data):
data = sorted(data)
n = len(data)
return data[n//2]

mean có vẻ “toán học” hơn, median có vẻ trực quan hơn. Mỗi giá trị sẽ được sử dụng trong từng trường hợp với yêu cầu cụ thể.

mode /məʊd/

Trong xác suất tiếng Việt gọi là “mốt” 😂
Giá trị xuất hiện nhiều lần nhất trong tập dữ liệu.

def mode(data):
dmax = data[0]
for d in data:
if data.count(d) > data.count(dmax):
dmax = d
return dmax
mode(data)
# 0.25

Với mode, ta có thể xử lý cả tập dữ liệu không phải số (nominal /ˈnɒmɪn(ə)l/)

mode(["red", "blue", "blue", "red", "green", "red", "red"])
# 'red'

Vậy nếu một tập có nhiều giá trị cùng xuất hiện nhiều lần (số lần bằng nhau) thì mode sẽ là giá trị nào?

Deviation /diːvɪˈeɪʃ(ə)n/

Nếu chỉ đại diện 1 tập dữ liệu bằng giá trị mean hay median, thì 2 tập sau được coi là như nhau:

mean([1,5,9]) == mean([3,4,5,6,7])

Rõ ràng ta cần thêm một thước đo để thể hiện việc tập trung hay phân tán của các giá trị so với điểm ở giữa. Suy nghĩ đơn giản, có thể tính giá trị trung bình của độ lệch mỗi data point so với mean:

def mydev(data):
mu = mean(data)
return sum([point-mu for point in data])/len(data)
mydev([1,5,9])
# 0.0

Nhưng bởi mean là giá trị trung bình, nên tổng các “độ lệch” này sẽ luôn bằng 0. Cách tính tự nghĩ này không ổn, ta thử một cách khác, dùng trung bình các giá trị tuyệt đối của các độ lệch: [1]

def mydev(data): # this is MAD 
mu = mean(data)
return sum([abs(point-mu) for point in data])/len(data)
mydev([1,5,9])
# 2.6666666666666665

Với giá trị 2.6666666666666665, có thể hiểu rằng các điểm trong tập dữ liệu được phân bố cách điểm trung tâm (ở ví dụ này là mean) một khoảng trung bình là ~2.6

Công thức tự nghĩ này, thực chất có một cái tên chính thống trong khoa học là: Mean absolute deviation — trung bình độ lệch tuyệt đối, viết tắt là MAD. Độ lệch ở đây có thể hiểu là độ lệch so với giá trị trung tâm, tính bằng mean HOẶC median (tuỳ trường hợp cụ thể sẽ ghi rõ). Giá trị MAD được cho là “tốt” để mô tả độ phân tán của bộ dữ liệu, ít bị ảnh hưởng bởi các giá trị “lệch”.

Khi deviation càng lớn thì dữ liệu càng nằm phân tán, deviation nhỏ tức là dữ liệu tập trung quanh điểm trung tâm.

Phương sai và độ lệch (tiêu) chuẩn

variance /ˈvɛːrɪəns/ và standard deviation /diːvɪˈeɪʃ(ə)n/

Đây là hai khái niệm phổ biến trong mọi cuốn sách viết về thống kê.
Dưới góc độ của một người mới bắt đầu học, tôi không hiểu lý do cặn kẽ tại sao chúng được sử dụng. Hầu hết, các cuốn sách sẽ chỉ giới thiệu cái tên, ký hiệu và công thức mà không giải thích tại sao. Có thể vì đây là các khái niệm đã có từ lâu, được phổ biến rộng rãi.
Khái niệm variance (phương sai, thường viết tắt là var), theo tôi hiểu là “bình phương của sai lệch (độ lệch)”, được giới thiệu là một công thức tính: giá trị trung bình của tổng các bình phương độ lệch

def variance(data):
mu = mean(data)
return sum([(point-mu)**2 for point in data])/len(data)
variance([1,5,9])
# 10.666666666666666

Khái niệm standard deviation (độ lệch CHUẨN, thường viết tắt là STD hay SD), không hiểu từ đâu ra mà được cho là “tiêu chuẩn” (standard). Khái niệm này được định nghĩa bằng công thức tính: căn bậc 2 của variance:

import math
def stddev(data): # standard deviation
return math.sqrt(variance(data))
stddev([1,5,9])
# 3.265986323710904

STD là một cách tính deviation theo kiểu khác (so với MAD). Nhưng ý nghĩa thì tương tự MAD, giá trị của nó biểu hiện độ phân tán của dữ liệu xung quanh điểm trung tâm. STD có ký hiệu toán học: sigma σ. Và variance, sẽ được ký hiệu là sigma bình phương σ².

Ta biết ý nghĩa của giá trị STD lớn hay nhỏ phản ánh tập dữ liệu phân bố tập trung quanh điểm trung tâm hay rời xa nó (ở đây là mean). Nhưng giá trị variance bằng 10 khác gì so với nó bằng 16? và đơn vị của nó là gì?
Giả sử tập dữ liệu [1,5,9] là giá trị chiều cao (cm) của các (3) cây mạ sau 5 ngày. Thì variance có đơn vị là cm² — rõ ràng đơn vị đo diện tích này không có ý nghĩa gì về mặt thống kê khi đang xử lý chiều cao của cây mạ. Variance là một giá trị có thể hữu ích khi đưa vào các công thức tính toán, nhưng không mang nhiều ý nghĩa về mặt thống kê.
STD với cách tính trên, thể hiện các điểm được phân bố đâu đó cách điểm mean một khoảng trung bình là ±3.2 cm.

Giá trị MAD được cho là “tốt” hơn để mô tả độ phân tán của bộ dữ liệu, ít bị ảnh hưởng bởi các giá trị khác biệt, còn STD thích hợp khi tính toán các công thức toán học và được dùng nhiều trong lý thuyết thống kê hơn. Giá trị variance để làm gì, có lẽ phải tiếp tục khám phá thêm mới biết được.

Với mean/median và deviation, ta đã có một hình dung chính xác hơn về tập dữ liệu, có điểm trung tâm ở đâu, dữ liệu phân bố thưa hay dày quanh điểm trung tâm. Thế nhưng với những giá trị ấy, ta không thể hình dung dữ liệu nằm tập trung về phía trái điểm trung tâm hay rải đều về 2 phía. Bởi vậy cần thêm khái niệm “phân phối” để định hình bộ dữ liệu có “hình dáng” thế nào, các điểm dữ liệu được phân bố ở đâu.
Chi tiết về các “phân phối” sẽ được khám phá ở bài sau.

Bài viết tham khảo phần lớn từ tài liệu của thư viện mới trong Python 3.4: statistics https://docs.python.org/3/library/statistics.html

Code dựa trên code của thư viện Python (nhưng đã làm đơn giản hơn nhiều): https://github.com/python/cpython/tree/3.6/Lib/statistics.py

Còn tiếp…
HVN at http://www.familug.org/ and http://pymi.vn

Đăng ký học #Python tại #HàNội , lớp khai giảng giữa tháng 4, 2017: https://pymi.vn/

Nhập email vào http://invite.pymi.vn/ để nhận thư mời tham gia forum hỏi đáp Python, Django, Golang, Linux …

Tham khảo 
https://en.wikipedia.org/wiki/Variance
https://en.wikipedia.org/wiki/Deviation_(statistics)
http://mathworld.wolfram.com/Variance.html
http://mathworld.wolfram.com/StandardDeviation.html
https://en.wikipedia.org/wiki/Average_absolute_deviation#Mean_absolute_deviation_around_the_mean
http://greenteapress.com/wp/think-stats-2e/


Chia sẻ:

Bình luận của bạn: