Chuyển đến nội dung chính

Hướng dẫn Scikit-Learn: Phân tích Bóng chày Phần 1

Hướng dẫn scikit-learn dự đoán số trận thắng MLB mỗi mùa bằng cách mô hình hóa dữ liệu với mô hình phân cụm KMeans và các mô hình hồi quy tuyến tính.
· 14 phút đọc

Khám phá cùng AI

Ngôn ngữ lập trình Python là một lựa chọn tuyệt vời cho khoa học dữ liệu và phân tích dự đoán, vì đi kèm với nhiều gói đáp ứng hầu hết nhu cầu phân tích dữ liệu của bạn. Với học máy trong Python, Scikit-learn (sklearn) là lựa chọn mạnh mẽ, được xây dựng trên NumPy, SciPy và Matplotlib (tương ứng là mảng N chiều, tính toán khoa học và trực quan hóa dữ liệu).

Trong hướng dẫn này, bạn sẽ thấy cách dễ dàng nạp dữ liệu từ cơ sở dữ liệu bằng sqlite3, cách khám phá dữ liệu và cải thiện chất lượng dữ liệu với pandas và matplotlib, và cách sử dụng gói Scikit-Learn để rút ra một số thông tin giá trị từ dữ liệu của bạn.

Nếu bạn muốn học một khóa học máy, hãy xem khóa Học có giám sát với scikit-learn của DataCamp.

Phần 1: Dự đoán số trận thắng mỗi mùa của các đội MLB

Trong dự án này, bạn sẽ thử một số mô hình học máy từ sklearn để dự đoán số trận mà một đội Bóng chày Nhà nghề (MLB) thắng trong mùa giải, dựa trên thống kê của đội và các biến khác trong mùa đó. Nếu tôi là người thích cá cược (mà tôi chắc chắn là người thích cá cược), tôi có thể xây dựng một mô hình sử dụng dữ liệu lịch sử từ các mùa trước để dự báo mùa tới. Xét tính chất chuỗi thời gian của dữ liệu, bạn có thể tạo ra các chỉ báo như số trận thắng trung bình mỗi năm trong năm năm trước đó và các yếu tố tương tự để tạo ra một mô hình có độ chính xác cao. Tuy nhiên, điều đó nằm ngoài phạm vi của hướng dẫn này và bạn sẽ coi mỗi hàng là độc lập. Mỗi hàng dữ liệu của chúng ta sẽ tương ứng với một đội trong một năm cụ thể.

Sean Lahman đã tổng hợp dữ liệu này trên trang web của ông và nó đã được chuyển đổi thành cơ sở dữ liệu sqlite tại đây.

Nạp dữ liệu

Bạn sẽ đọc dữ liệu bằng cách truy vấn một cơ sở dữ liệu sqlite với gói sqlite3 và chuyển đổi sang DataFrame với pandas. Dữ liệu của bạn sẽ được lọc chỉ bao gồm các đội hiện còn hoạt động trong thời hiện đại và chỉ những năm mà đội chơi từ 150 trận trở lên.

Đầu tiên, tải xuống tệp “lahman2016.sqlite” (tại đây). Sau đó, nạp Pandas và đổi tên thành pd cho tiện. Bạn có thể nhớ rằng pd là bí danh thường dùng cho Pandas. Cuối cùng, nạp sqlite3 và kết nối đến cơ sở dữ liệu như sau:

# import `pandas` and `sqlite3`import pandas as pdimport sqlite3# Connecting to SQLite Databaseconn = sqlite3.connect('lahman2016.sqlite')

Tiếp theo, bạn viết một truy vấn, thực thi và lấy kết quả.

# Querying Database for all seasons where a team played 150 or more games and is still active today. query = '''select * from Teams inner join TeamsFranchiseson Teams.franchID == TeamsFranchises.franchIDwhere Teams.G >= 150 and TeamsFranchises.active == 'Y';'''# Creating dataframe from query.Teams = conn.execute(query).fetchall()

Mẹo: Nếu bạn muốn tìm hiểu thêm về việc dùng SQL với Python, hãy cân nhắc học khóa Nhập môn cơ sở dữ liệu trong Python của DataCamp.

Sử dụng pandas, bạn sẽ chuyển kết quả sang DataFrame và in ra 5 hàng đầu tiên bằng phương thức head():

# Convert `Teams` to DataFrame
teams_df = pd.DataFrame(_____)

# Print out first 5 rows
print(_______________)

Mỗi cột chứa dữ liệu liên quan đến một đội và một năm cụ thể. Một số biến quan trọng hơn được liệt kê bên dưới. Danh sách đầy đủ biến có thể tìm thấy tại đây.

  • yearID - Năm
  • teamID - Đội
  • franchID - Thương hiệu (liên kết tới bảng TeamsFranchise)
  • G - Số trận đã chơi
  • W - Số trận thắng
  • LgWin - Vô địch giải (Y hoặc N)
  • WSWin - Vô địch World Series (Y hoặc N)
  • R - Số lần ghi điểm (runs)
  • AB - Số lần đánh bóng (at bats)
  • H - Số cú đánh trúng (hits) của cầu thủ đánh
  • HR - Số cú home run của cầu thủ đánh
  • BB - Số lần đi bộ (walks) của cầu thủ đánh
  • SO - Số lần strikeout của cầu thủ đánh
  • SB - Số lần cướp gôn (stolen bases)
  • CS - Số lần bị bắt khi cướp gôn (caught stealing)
  • HBP - Số lần bị ném trúng người (hit by pitch)
  • SF - Sacrifice flies
  • RA - Số điểm đối thủ ghi được
  • ER - Số điểm trách nhiệm của pitcher (earned runs) cho phép
  • ERA - Chỉ số ERA (earned run average)
  • CG - Số trận ném hoàn chỉnh (complete games)
  • SHO - Số trận không cho đối thủ ghi điểm (shutouts)
  • SV - Số lần cứu nguy (saves)
  • IPOuts - Số lần loại đối thủ khi ném (innings pitched x 3)
  • HA - Số cú đánh trúng cho phép
  • HRA - Số cú home run cho phép
  • BBA - Số lần đi bộ cho phép
  • SOA - Số lần strikeout của pitcher
  • E - Lỗi (errors)
  • DP - Double play
  • FP - Tỉ lệ phòng thủ (fielding percentage)
  • name - Tên đầy đủ của đội

Với những bạn chưa quen với bóng chày, dưới đây là phần giải thích ngắn về cách thức trò chơi, kèm một số biến liên quan.

Bóng chày được chơi giữa hai đội (trong dữ liệu bạn sẽ thấy ở name hoặc teamID) mỗi đội 9 người. Hai đội luân phiên tấn công (đánh) và phòng thủ. Đội tấn công cố gắng ghi điểm (run) bằng cách lần lượt đánh quả bóng do pitcher của đội phòng thủ ném, sau đó chạy ngược chiều kim đồng hồ quanh bốn gôn: nhất, nhì, ba và gôn nhà (home plate). Đội phòng thủ cố gắng ngăn chặn điểm bằng cách loại (out) người đánh hoặc người chạy gôn theo một số cách, và một run (R) được ghi khi người chơi chạy vòng quanh các gôn và trở về gôn nhà. Một cầu thủ của đội tấn công khi vào gôn an toàn sẽ cố gắng tiến tới các gôn tiếp theo trong lượt đánh của đồng đội, ví dụ nhờ một cú đánh trúng (H), một pha cướp gôn (SB), hoặc bằng cách khác.

baseball

Hai đội đổi lượt tấn công và phòng thủ khi đội phòng thủ ghi được ba out. Mỗi lượt đánh của cả hai đội, bắt đầu từ đội khách, được tính là một hiệp (inning). Một trận có chín hiệp, và đội có nhiều run hơn khi trận đấu kết thúc sẽ thắng. Bóng chày không có đồng hồ thi đấu và dù hầu hết trận kết thúc sau hiệp chín, nếu tỉ số hòa sau chín hiệp thì sẽ vào hiệp phụ và tiếp tục vô thời hạn cho đến khi một đội dẫn trước khi kết thúc một hiệp phụ.

Để xem giải thích chi tiết về luật bóng chày, hãy xem luật chính thức của Major League Baseball.

Làm sạch và chuẩn bị dữ liệu

Như bạn thấy ở trên, DataFrame chưa có tiêu đề cột. Bạn có thể thêm tiêu đề bằng cách truyền một danh sách tên cột vào thuộc tính columns của pandas.

# Adding column names to dataframe
cols = ['yearID','lgID','teamID','franchID','divID','Rank','G','Ghome','W','L','DivWin','WCWin','LgWin','WSWin','R','AB','H','2B','3B','HR','BB','SO','SB','CS','HBP','SF','RA','ER','ERA','CG','SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','name','park','attendance','BPF','PPF','teamIDBR','teamIDlahman45','teamIDretro','franchID','franchName','active','NAassoc']
teams_df.columns = ____

# Print the first rows of `teams_df`
print(______________)

# Print the length of `teams_df`
print(len(________))

Hàm len() sẽ cho bạn biết bạn đang xử lý bao nhiêu hàng: 2.287 không phải là quá lớn, nên hy vọng không có quá nhiều giá trị null.

Trước khi đánh giá chất lượng dữ liệu, hãy loại bỏ những cột không cần thiết hoặc được suy ra từ cột đích (Wins). Đây là lúc kiến thức về dữ liệu bạn đang làm việc trở nên rất giá trị. Không quan trọng bạn biết lập trình hay thống kê đến đâu nếu bạn không hiểu dữ liệu của mình. Việc là một người hâm mộ bóng chày lâu năm đã giúp tôi rất nhiều trong dự án này.

# Dropping your unnecesary column variables.
drop_cols = ['lgID','franchID','divID','Rank','Ghome','L','DivWin','WCWin','LgWin','WSWin','SF','name','park','attendance','BPF','PPF','teamIDBR','teamIDlahman45','teamIDretro','franchID','franchName','active','NAassoc']

df = teams_df.drop(drop_cols, axis=1)

# Print out first rows of `df`
print(_________)

Như bạn đã đọc ở trên, các giá trị null ảnh hưởng đến chất lượng dữ liệu, từ đó có thể gây vấn đề cho thuật toán học máy.

Vì vậy, tiếp theo bạn sẽ loại bỏ chúng. Có vài cách để loại các giá trị null, nhưng có lẽ nên hiển thị số lượng giá trị null của mỗi cột trước để bạn quyết định cách xử lý tốt nhất.

# Print out null values of all columns of `df`
print(_________.sum(axis=0).tolist())

Và đây là sự đánh đổi bạn sẽ thấy: bạn cần dữ liệu sạch, nhưng bạn cũng không có quá nhiều dữ liệu để bỏ đi. Hai cột có số lượng giá trị null tương đối nhỏ. Có 110 giá trị null ở cột SO (Strikeout) và 22 ở cột DP (Double play). Hai cột có số lượng null tương đối lớn: có 419 giá trị null ở cột CS (Caught stealing) và 1777 ở cột HBP (Hit by pitch).

Nếu bạn loại các hàng mà cột chỉ có một lượng nhỏ giá trị null, bạn sẽ mất hơn 5% dữ liệu. Vì bạn đang cố dự đoán số trận thắng, số run ghi được và số run để đối thủ ghi có tương quan mạnh với biến mục tiêu. Bạn muốn dữ liệu ở các cột đó thật chính xác.

Strikeout (SO) và double play (DP) thì không quá quan trọng.

Tôi cho rằng tốt hơn là giữ các hàng này và điền giá trị null bằng trung vị của từng cột với phương thức fillna(). Caught stealing (CS) và hit by pitch (HBP) cũng không phải biến quá quan trọng. Với quá nhiều giá trị null ở các cột này, tốt nhất là loại bỏ hẳn các cột.

# Eliminating columns with null values
df = df.drop(['CS','HBP'], axis=1)

# Filling null values
df['SO'] = df['SO'].fillna(df['SO'].median())
df['DP'] = df['DP'].fillna(df['DP'].median())

# Print out null values of all columns of `df`
print(df.isnull().sum(axis=0).tolist())

Khám phá và trực quan hóa dữ liệu

Bây giờ dữ liệu đã được làm sạch, bạn có thể bắt đầu khám phá. Bạn có thể hiểu bộ dữ liệu tốt hơn với một vài trực quan hóa đơn giản. matplotlib là thư viện tuyệt vời cho trực quan hóa dữ liệu.

Bạn nạp matplotlib.pyplot và đặt bí danh là plt cho gọn. Nếu bạn làm việc với sổ tay Jupyter, bạn cần dùng magic %matplotlib inline.

Bạn sẽ bắt đầu bằng cách vẽ biểu đồ histogram của cột mục tiêu để xem phân phối số trận thắng.

# import the pyplot module from matplotlibimport matplotlib.pyplot as plt# matplotlib plots inline  %matplotlib inline# Plotting distribution of winsplt.hist(df['W'])plt.xlabel('Wins')plt.title('Distribution of Wins')plt.show()

distribution graph

Lưu ý rằng nếu bạn không dùng sổ tay Jupyter, bạn phải gọi plt.show() để hiển thị biểu đồ.

In ra số trận thắng trung bình (W) mỗi năm. Bạn có thể dùng phương thức mean() cho việc này.

print(df['_'].______)

Việc tạo các khoảng (bins) cho cột mục tiêu khi khám phá dữ liệu có thể hữu ích, nhưng bạn cần đảm bảo không đưa bất kỳ đặc trưng nào được tạo ra từ cột mục tiêu vào quá trình huấn luyện mô hình. Bao gồm một cột nhãn được tạo ra từ cột mục tiêu trong tập huấn luyện chẳng khác nào cho mô hình biết sẵn đáp án.

Để tạo nhãn thắng, bạn sẽ viết một hàm assign_win_bins nhận một giá trị số nguyên (số trận thắng) và trả về số nguyên từ 1–5 tùy theo giá trị đầu vào.

Tiếp theo, bạn sẽ tạo cột mới win_bins bằng cách dùng phương thức apply() trên cột số trận thắng và truyền vào hàm assign_win_bins().

# Creating bins for the win column
def assign_win_bins(_):
    if W < 50:
        return 1
    if W >= 50 and W <= 69:
        return 2
    if W >= 70 and W <= 89:
        return 3
    if W >= 90 and W <= 109:
        return 4
    if W >= 110:
        return 5
        
# Apply `assign_win_bins` to `df['W']`    
df['win_bins'] = df['_'].apply(______________)

Giờ hãy vẽ một biểu đồ scatter với năm trên trục x và số trận thắng trên trục y, đồng thời tô màu theo cột win_bins.

# Plotting scatter graph of Year vs. Winsplt.scatter(df['yearID'], df['W'], c=df['win_bins'])plt.title('Wins Scatter Plot')plt.xlabel('Year')plt.ylabel('Wins')plt.show()

scikit-learn project

Như bạn thấy ở biểu đồ scatter trên, có rất ít mùa giải trước năm 1900 và trò chơi khi đó rất khác. Vì vậy, hợp lý là loại bỏ những hàng đó khỏi bộ dữ liệu.

# Filter for rows where 'yearID' is greater than 1900
df = df[___________________]

Khi làm việc với dữ liệu liên tục và tạo mô hình tuyến tính, các giá trị số nguyên như năm có thể gây vấn đề. Khó có khả năng số 1950 sẽ có cùng mối quan hệ với phần còn lại của dữ liệu như mô hình suy ra.

Bạn có thể tránh các vấn đề này bằng cách tạo biến mới để gán nhãn dữ liệu dựa trên giá trị yearID.

Bất kỳ ai theo dõi bóng chày đều biết rằng khi MLB phát triển, đã xuất hiện những giai đoạn (era) mà số run mỗi trận tăng hoặc giảm đáng kể. Kỷ nguyên “dead-ball” đầu những năm 1900 là ví dụ về thời kỳ ít điểm, còn kỷ nguyên “steroid” vào bước ngoặt thế kỷ 21 là ví dụ về thời kỳ nhiều điểm.

Hãy tạo một biểu đồ bên dưới để cho thấy mức độ ghi điểm theo từng năm.

Bạn sẽ bắt đầu bằng cách tạo các từ điển runs_per_year và games_per_year. Lặp qua dataframe bằng phương thức iterrows(). Điền từ điển runs_per_year với khóa là các năm và giá trị là số run được ghi trong năm đó. Điền từ điển games_per_year với khóa là các năm và giá trị là số trận được chơi trong năm đó.

# Create runs per year and games per year dictionaries
runs_per_year = {}
games_per_year = {}

for i, row in df.iterrows():
    year = row['yearID']
    runs = row['R']
    games = row['G']
    if year in runs_per_year:
        runs_per_year[year] = runs_per_year[year] + runs
        games_per_year[year] = games_per_year[year] + games
    else:
        runs_per_year[year] = runs
        games_per_year[year] = games
        
print(runs_per_year)
print(games_per_year)

Tiếp theo, tạo một từ điển tên mlb_runs_per_game. Lặp qua từ điển games_per_year bằng phương thức items(). Điền mlb_runs_per_game với khóa là các năm và giá trị là số run ghi được trên mỗi trận trong toàn giải.

# Create MLB runs per game (per year) dictionary
mlb_runs_per_game = {}
for k, v in games_per_year.items():
    year = k
    games = v
    runs = runs_per_year[year]
    mlb_runs_per_game[year] = runs / games
    
print(mlb_runs_per_game)

Cuối cùng, tạo biểu đồ từ từ điển mlb_runs_per_game bằng cách đặt năm trên trục x và số run mỗi trận trên trục y.

# Create lists from mlb_runs_per_game dictionarylists = sorted(mlb_runs_per_game.items())x, y = zip(*lists)# Create line plot of Year vs. MLB runs per Gameplt.plot(x, y)plt.title('MLB Yearly Runs per Game')plt.xlabel('Year')plt.ylabel('MLB Runs per Game')plt.show()

baseball analytics scikit-learn

Thêm tính năng mới

Bây giờ khi bạn đã hiểu rõ hơn về xu hướng ghi điểm, bạn có thể tạo các biến mới để chỉ ra giai đoạn cụ thể mà mỗi hàng dữ liệu thuộc về dựa trên yearID. Bạn sẽ làm theo quy trình giống như khi tạo cột win_bins ở trên.

Lần này, bạn sẽ tạo các cột giả: một cột mới cho mỗi giai đoạn. Bạn có thể dùng phương thức get_dummies() cho việc này.

# Creating "year_label" column, which will give your algorithm information about how certain years are related 
# (Dead ball eras, Live ball/Steroid Eras)

def assign_label(____):
    if year < 1920:
        return 1
    elif year >= 1920 and year <= 1941:
        return 2
    elif year >= 1942 and year <= 1945:
        return 3
    elif year >= 1946 and year <= 1962:
        return 4
    elif year >= 1963 and year <= 1976:
        return 5
    elif year >= 1977 and year <= 1992:
        return 6
    elif year >= 1993 and year <= 2009:
        return 7
    elif year >= 2010:
        return 8
        
# Add `year_label` column to `df`    
df['year_label'] = df['yearID'].apply(___________)

dummy_df = pd.get_dummies(df['year_label'], prefix='era')

# Concatenate `df` and `dummy_df`
df = pd.concat([df, dummy_df], axis=1)

print(df.head())

Vì bạn đã tính số run mỗi trận của MLB cho từng năm, hãy thêm dữ liệu đó vào bộ dữ liệu.

# Create column for MLB runs per game from the mlb_runs_per_game dictionary
def assign_mlb_rpg(year):
    return mlb_runs_per_game[year]

df['mlb_rpg'] = df['yearID'].apply(assign_mlb_rpg)

Giờ bạn sẽ chuyển các năm thành thập niên bằng cách tạo các cột giả cho mỗi thập niên. Sau đó, bạn có thể loại bỏ những cột không còn cần thiết.

# Convert years into decade bins and creating dummy variables
def assign_decade(year):
    if year < 1920:
        return 1910
    elif year >= 1920 and year <= 1929:
        return 1920
    elif year >= 1930 and year <= 1939:
        return 1930
    elif year >= 1940 and year <= 1949:
        return 1940
    elif year >= 1950 and year <= 1959:
        return 1950
    elif year >= 1960 and year <= 1969:
        return 1960
    elif year >= 1970 and year <= 1979:
        return 1970
    elif year >= 1980 and year <= 1989:
        return 1980
    elif year >= 1990 and year <= 1999:
        return 1990
    elif year >= 2000 and year <= 2009:
        return 2000
    elif year >= 2010:
        return 2010
    
df['decade_label'] = df['yearID'].apply(assign_decade)
decade_df = pd.get_dummies(df['decade_label'], prefix='decade')
df = pd.concat([df, decade_df], axis=1)

# Drop unnecessary columns
df = df.drop(['yearID','year_label','decade_label'], axis=1)

Điều cốt lõi trong bóng chày là bạn ghi được bao nhiêu run và để đối thủ ghi bao nhiêu run. Bạn có thể cải thiện đáng kể độ chính xác của mô hình bằng cách tạo các cột là tỷ số giữa những cột dữ liệu khác. Số run mỗi trận và số run để lọt mỗi trận sẽ là những đặc trưng rất hữu ích để thêm vào bộ dữ liệu.

Pandas giúp việc này rất đơn giản: bạn tạo một cột mới bằng cách lấy cột R chia cho cột G để tạo cột R_per_game.

# Create new features for Runs per Game and Runs Allowed per Game
df['R_per_game'] = df['R'] / df['G']
df['RA_per_game'] = df['RA'] / df['G']

Bây giờ hãy xem hai biến mới này liên hệ với cột mục tiêu số trận thắng như thế nào bằng cách vẽ vài biểu đồ phân tán. Vẽ số run mỗi trận trên trục x của một biểu đồ và số run để lọt mỗi trận trên trục x của biểu đồ còn lại. Trên mỗi trục y, vẽ cột W.

# Create scatter plots for runs per game vs. wins and runs allowed per game vs. winsfig = plt.figure(figsize=(12, 6))ax1 = fig.add_subplot(1,2,1)ax2 = fig.add_subplot(1,2,2)ax1.scatter(df['R_per_game'], df['W'], c='blue')ax1.set_title('Runs per Game vs. Wins')ax1.set_ylabel('Wins')ax1.set_xlabel('Runs per Game')ax2.scatter(df['RA_per_game'], df['W'], c='red')ax2.set_title('Runs Allowed per Game vs. Wins')ax2.set_xlabel('Runs Allowed per Game')plt.show()

clusters

Trước khi xây dựng bất kỳ mô hình học máy nào, việc xem mỗi biến tương quan với biến mục tiêu ra sao cũng hữu ích. Pandas hỗ trợ dễ dàng với phương thức corr().

df.corr()['W']

Một đặc trưng khác bạn có thể thêm vào bộ dữ liệu là các nhãn được suy ra từ thuật toán phân cụm K-means do sklearn cung cấp. K-means là thuật toán phân cụm đơn giản, chia dữ liệu theo số lượng trọng tâm k mà bạn chỉ định. Mỗi điểm dữ liệu được gán vào một cụm dựa trên trọng tâm có khoảng cách Euclid nhỏ nhất tới điểm đó.

Bạn có thể tìm hiểu thêm về phân cụm K-means tại đây.

Đầu tiên, tạo một DataFrame loại bỏ biến mục tiêu:

attributes = ['G','R','AB','H','2B','3B','HR','BB','SO','SB','RA','ER','ERA','CG',
'SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','era_1','era_2','era_3','era_4','era_5','era_6','era_7','era_8','decade_1910','decade_1920','decade_1930','decade_1940','decade_1950','decade_1960','decade_1970','decade_1980','decade_1990','decade_2000','decade_2010','R_per_game','RA_per_game','mlb_rpg']

data_attributes = df[attributes]

# Print the first rows of `df`
print(df.head())

Một yếu tố của phân cụm K-means mà bạn phải xác định trước khi dùng mô hình là số lượng cụm mong muốn. Bạn có thể ước lượng tốt hơn số cụm tối ưu bằng cách dùng hàm silhouette_score() của sklearn. Hàm này trả về hệ số silhouette trung bình trên toàn bộ mẫu. Bạn muốn điểm silhouette cao hơn, và điểm số sẽ giảm khi tăng số cụm.

# Import necessary modules from `sklearn` 
from sklearn.cluster import KMeans
from sklearn import metrics

# Create silhouette score dictionary
s_score_dict = {}
for i in range(2,11):
    km = KMeans(n_clusters=i, random_state=1)
    l = km.fit_predict(data_attributes)
    s_s = metrics.silhouette_score(data_attributes, l)
    s_score_dict[i] = [s_s]

# Print out `s_score_dict`
print(s_score_dict)

Bây giờ bạn có thể khởi tạo mô hình. Đặt số cụm là 6 và random state là 1. Xác định khoảng cách Euclid cho mỗi điểm dữ liệu bằng phương thức fit_transform() rồi trực quan hóa các cụm bằng biểu đồ phân tán.

# Create K-means model and determine euclidian distances for each data pointkmeans_model = KMeans(n_clusters=6, random_state=1)distances = kmeans_model.fit_transform(data_attributes)# Create scatter plot using labels from K-means model as colorlabels = kmeans_model.labels_plt.scatter(distances[:,0], distances[:,1], c=labels)plt.title('Kmeans Clusters')plt.show()

clusters

Bây giờ hãy thêm các nhãn từ cụm của bạn vào bộ dữ liệu như một cột mới. Đồng thời thêm chuỗi “labels” vào danh sách attributes để dùng sau.

# Add labels from K-means model to `df` DataFrame and attributes list
df['labels'] = labels
attributes.append('labels')

# Print the first rows of `df`
print(_________)

Trước khi xây dựng mô hình, bạn cần chia dữ liệu thành tập huấn luyện và kiểm tra. Lý do là nếu bạn huấn luyện và kiểm tra trên cùng một dữ liệu, mô hình rất dễ bị quá khớp: nó ghi nhớ dữ liệu thay vì học từ dữ liệu, dẫn đến mô hình quá phức tạp. Điều đó cũng giải thích vì sao mô hình quá khớp sẽ hoạt động kém khi dự đoán với dữ liệu mới.

Nhưng đừng lo, có nhiều cách để đánh giá chéo mô hình của bạn.

Lần này, bạn sẽ đơn giản lấy ngẫu nhiên 75 phần trăm dữ liệu làm tập train và dùng 25 phần trăm còn lại làm tập test. Tạo danh sách numeric_cols chứa tất cả các cột sẽ dùng trong mô hình. Tiếp theo, tạo DataFrame mới data từ DataFrame df với các cột trong danh sách numeric_cols. Sau đó, tạo các tập dữ liệu train và test bằng cách lấy mẫu từ DataFrame data.

# Create new DataFrame using only variables to be included in models
numeric_cols = ['G','R','AB','H','2B','3B','HR','BB','SO','SB','RA','ER','ERA','CG','SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','era_1','era_2','era_3','era_4','era_5','era_6','era_7','era_8','decade_1910','decade_1920','decade_1930','decade_1940','decade_1950','decade_1960','decade_1970','decade_1980','decade_1990','decade_2000','decade_2010','R_per_game','RA_per_game','mlb_rpg','labels','W']
data = df[numeric_cols]
print(data.head())

# Split data DataFrame into train and test sets
train = data.sample(frac=0.75, random_state=1)
test = data.loc[~data.index.isin(train.index)]

x_train = train[attributes]
y_train = train['W']
x_test = test[attributes]
y_test = test['W']

Chọn thước đo lỗi và mô hình

Mean Absolute Error (MAE) là thước đo bạn sẽ dùng để xác định độ chính xác của mô hình. Nó đo lường mức độ gần của các dự đoán so với kết quả thực tế. Cụ thể, với dữ liệu này, thước đo lỗi sẽ cho bạn giá trị tuyệt đối trung bình mà dự đoán của bạn chệch khỏi mục tiêu.

Điều này có nghĩa là nếu trung bình dự đoán của bạn lệch khỏi con số mục tiêu 5 trận thắng, thì thước đo lỗi sẽ là 5.

Mô hình đầu tiên bạn sẽ huấn luyện là hồi quy tuyến tính. Bạn có thể import LinearRegression và mean_absolute_error lần lượt từ sklearn.linear_model và sklearn.metrics, rồi tạo mô hình lr. Tiếp theo, bạn sẽ fit mô hình, tạo dự đoán và xác định sai số tuyệt đối trung bình của mô hình.

# Import `LinearRegression` from `sklearn.linear_model`
from sklearn.linear_model import ___________________

# Import `mean_absolute_error` from `sklearn.metrics`
from sklearn.metrics import mean_absolute_error

# Create Linear Regression model, fit model, and make predictions
lr = LinearRegression(normalize=True)
lr.fit(x_train, y_train)
predictions = lr.predict(x_test)

# Determine mean absolute error
mae = mean_absolute_error(y_test, predictions)

# Print `mae`
print(___)

Nếu bạn còn nhớ ở trên, số trận thắng trung bình vào khoảng 79. Trung bình, mô hình chỉ lệch 2,687 trận thắng.

Bây giờ hãy thử mô hình hồi quy Ridge. Import RidgeCV từ sklearn.linear_model và tạo mô hình rrm. Mô hình RidgeCV cho phép bạn đặt tham số alpha, là tham số độ phức tạp kiểm soát mức độ thu hẹp (shrinkage) (đọc thêm tại đây). Mô hình sẽ dùng cross-validation để xác định giá trị alpha tối ưu trong các giá trị bạn cung cấp.

Một lần nữa, hãy fit mô hình, tạo dự đoán và xác định sai số tuyệt đối trung bình.

# Import `RidgeCV` from `sklearn.linear_model`
from sklearn.linear_model import _______

# Create Ridge Linear Regression model, fit model, and make predictions
rrm = RidgeCV(alphas=(0.01, 0.1, 1.0, 10.0), normalize=True)
rrm.fit(x_train, y_train)
predictions_rrm = rrm.predict(x_test)

# Determine mean absolute error
mae_rrm = mean_absolute_error(y_test, predictions_rrm)
print(________)

Mô hình này hoạt động nhỉnh hơn một chút, với độ lệch trung bình 2,673 trận thắng.

Phân tích thể thao & Scikit-Learn

Phần này khép lại phần đầu tiên của loạt hướng dẫn, trong đó bạn đã thấy cách dùng scikit-learn để phân tích dữ liệu thể thao. Bạn đã import dữ liệu từ cơ sở dữ liệu SQLite, làm sạch, khám phá trực quan một số khía cạnh và xây dựng thêm một số đặc trưng mới. Bạn đã học cách tạo mô hình phân cụm K-means, một vài mô hình Hồi quy tuyến tính, và cách kiểm tra dự đoán bằng thước đo sai số tuyệt đối trung bình.

Ở phần thứ hai, bạn sẽ xem cách dùng các mô hình phân loại để dự đoán những cầu thủ nào được vinh danh vào MLB Hall of Fame.

Chủ đề