Bài viết gần đây

| Thống kê lượng với DataFrame trên Python

Được viết bởi thanhdt vào ngày 16/11/2025 lúc 10:48 | 10 lượt xem


Thống kê lượng với DataFrame trên Python

Thống kê lượng (descriptive statistics) là một phần quan trọng trong phân tích dữ liệu, giúp bạn hiểu được đặc điểm và xu hướng của dữ liệu. Với Pandas DataFrame, việc thực hiện các phép thống kê trở nên đơn giản và hiệu quả. Bài viết này sẽ hướng dẫn bạn cách sử dụng các hàm thống kê trong Pandas để phân tích dữ liệu.

Thống kê mô tả là gì?

Thống kê mô tả là các phép toán giúp tóm tắt và mô tả các đặc điểm chính của dữ liệu mà không cần suy luận về toàn bộ quần thể. Các thống kê mô tả phổ biến bao gồm:

  • Trung bình (Mean): Giá trị trung bình của dữ liệu
  • Trung vị (Median): Giá trị ở giữa khi sắp xếp dữ liệu
  • Độ lệch chuẩn (Standard Deviation): Đo lường độ phân tán của dữ liệu
  • Phương sai (Variance): Bình phương của độ lệch chuẩn
  • Tứ phân vị (Quartiles): Chia dữ liệu thành 4 phần bằng nhau
  • Min/Max: Giá trị nhỏ nhất và lớn nhất

Cài đặt và import thư viện

Trước khi bắt đầu, bạn cần import các thư viện cần thiết:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Thiết lập hiển thị
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)

Tạo dữ liệu mẫu

Để minh họa, chúng ta sẽ tạo một DataFrame mẫu về doanh số bán hàng:

# Tạo dữ liệu mẫu
np.random.seed(42)
data = {
    'Ngày': pd.date_range('2024-01-01', periods=100, freq='D'),
    'Doanh_thu': np.random.normal(50000, 10000, 100),
    'Số_lượng': np.random.randint(100, 500, 100),
    'Chi_phí': np.random.normal(30000, 5000, 100),
    'Khu_vực': np.random.choice(['Miền Bắc', 'Miền Trung', 'Miền Nam'], 100),
    'Sản_phẩm': np.random.choice(['A', 'B', 'C', 'D'], 100)
}

df = pd.DataFrame(data)

# Tính thêm cột Lợi nhuận
df['Lợi_nhuận'] = df['Doanh_thu'] - df['Chi_phí']
df['Tỷ_lệ_lợi_nhuận'] = (df['Lợi_nhuận'] / df['Doanh_thu']) * 100

# Hiển thị 5 dòng đầu
print(df.head())

Thống kê mô tả cơ bản với describe()

Hàm describe() là cách nhanh nhất để xem tổng quan về dữ liệu:

# Thống kê mô tả cho tất cả các cột số
print(df.describe())

# Thống kê mô tả cho một cột cụ thể
print(df['Doanh_thu'].describe())

# Thống kê mô tả với các tứ phân vị tùy chỉnh
print(df.describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9]))

# Thống kê mô tả bao gồm cả dữ liệu không phải số
print(df.describe(include='all'))

Kết quả của describe() bao gồm:

  • count: Số lượng giá trị không phải NaN
  • mean: Giá trị trung bình
  • std: Độ lệch chuẩn
  • min: Giá trị nhỏ nhất
  • 25%: Tứ phân vị thứ nhất (Q1)
  • 50%: Trung vị (Q2)
  • 75%: Tứ phân vị thứ ba (Q3)
  • max: Giá trị lớn nhất

Các hàm thống kê cơ bản

Trung bình (Mean)

# Trung bình của một cột
mean_revenue = df['Doanh_thu'].mean()
print(f"Trung bình doanh thu: {mean_revenue:,.2f}")

# Trung bình của nhiều cột
mean_multiple = df[['Doanh_thu', 'Chi_phí', 'Lợi_nhuận']].mean()
print(mean_multiple)

# Trung bình theo trục (axis)
# axis=0: tính theo cột (mặc định)
# axis=1: tính theo hàng
mean_by_row = df[['Doanh_thu', 'Chi_phí']].mean(axis=1)
print(mean_by_row.head())

Trung vị (Median)

# Trung vị của một cột
median_revenue = df['Doanh_thu'].median()
print(f"Trung vị doanh thu: {median_revenue:,.2f}")

# Trung vị của nhiều cột
median_multiple = df[['Doanh_thu', 'Chi_phí', 'Lợi_nhuận']].median()
print(median_multiple)

Độ lệch chuẩn và Phương sai

# Độ lệch chuẩn
std_revenue = df['Doanh_thu'].std()
print(f"Độ lệch chuẩn doanh thu: {std_revenue:,.2f}")

# Phương sai
var_revenue = df['Doanh_thu'].var()
print(f"Phương sai doanh thu: {var_revenue:,.2f}")

# Hệ số biến thiên (CV) = std/mean
cv = df['Doanh_thu'].std() / df['Doanh_thu'].mean()
print(f"Hệ số biến thiên: {cv:.2%}")

Min, Max và Range

# Giá trị nhỏ nhất
min_revenue = df['Doanh_thu'].min()
print(f"Doanh thu nhỏ nhất: {min_revenue:,.2f}")

# Giá trị lớn nhất
max_revenue = df['Doanh_thu'].max()
print(f"Doanh thu lớn nhất: {max_revenue:,.2f}")

# Khoảng biến thiên (Range)
range_revenue = df['Doanh_thu'].max() - df['Doanh_thu'].min()
print(f"Khoảng biến thiên: {range_revenue:,.2f}")

# Hoặc sử dụng ptp (peak to peak)
range_ptp = df['Doanh_thu'].ptp()
print(f"Khoảng biến thiên (ptp): {range_ptp:,.2f}")

Tứ phân vị (Quartiles)

# Tứ phân vị thứ nhất (Q1 - 25%)
q1 = df['Doanh_thu'].quantile(0.25)
print(f"Q1 (25%): {q1:,.2f}")

# Trung vị (Q2 - 50%)
q2 = df['Doanh_thu'].quantile(0.5)
print(f"Q2 (50%): {q2:,.2f}")

# Tứ phân vị thứ ba (Q3 - 75%)
q3 = df['Doanh_thu'].quantile(0.75)
print(f"Q3 (75%): {q3:,.2f}")

# Khoảng tứ phân vị (IQR - Interquartile Range)
iqr = q3 - q1
print(f"IQR: {iqr:,.2f}")

# Tất cả các tứ phân vị cùng lúc
quartiles = df['Doanh_thu'].quantile([0.25, 0.5, 0.75])
print(quartiles)

Tổng và Đếm

# Tổng
total_revenue = df['Doanh_thu'].sum()
print(f"Tổng doanh thu: {total_revenue:,.2f}")

# Đếm số lượng (không tính NaN)
count = df['Doanh_thu'].count()
print(f"Số lượng giá trị: {count}")

# Đếm tất cả (kể cả NaN)
count_all = df['Doanh_thu'].size
print(f"Tổng số phần tử: {count_all}")

# Đếm số giá trị duy nhất
unique_count = df['Khu_vực'].nunique()
print(f"Số khu vực duy nhất: {unique_count}")

# Đếm số lần xuất hiện của mỗi giá trị
value_counts = df['Khu_vực'].value_counts()
print(value_counts)

Thống kê theo nhóm (GroupBy)

Một trong những tính năng mạnh mẽ nhất của Pandas là thống kê theo nhóm:

# Thống kê theo khu vực
stats_by_region = df.groupby('Khu_vực')['Doanh_thu'].agg(['mean', 'median', 'std', 'min', 'max'])
print(stats_by_region)

# Nhiều hàm thống kê cho nhiều cột
stats_multiple = df.groupby('Khu_vực')[['Doanh_thu', 'Chi_phí', 'Lợi_nhuận']].agg({
    'Doanh_thu': ['mean', 'sum', 'std'],
    'Chi_phí': ['mean', 'sum'],
    'Lợi_nhuận': ['mean', 'sum', 'min', 'max']
})
print(stats_multiple)

# Thống kê theo nhiều cột nhóm
stats_multi_group = df.groupby(['Khu_vực', 'Sản_phẩm'])['Doanh_thu'].agg(['mean', 'sum', 'count'])
print(stats_multi_group)

Sử dụng agg() cho thống kê tùy chỉnh

Hàm agg() cho phép bạn áp dụng nhiều hàm thống kê cùng lúc:

# Áp dụng nhiều hàm cho một cột
stats_custom = df['Doanh_thu'].agg(['mean', 'median', 'std', 'min', 'max', 'sum'])
print(stats_custom)

# Áp dụng hàm tùy chỉnh
def coefficient_of_variation(series):
    """Tính hệ số biến thiên"""
    return series.std() / series.mean()

custom_stats = df['Doanh_thu'].agg(['mean', 'std', coefficient_of_variation])
print(custom_stats)

# Với GroupBy
grouped_stats = df.groupby('Khu_vực')['Doanh_thu'].agg([
    'mean',
    'std',
    ('cv', coefficient_of_variation),
    ('range', lambda x: x.max() - x.min())
])
print(grouped_stats)

Thống kê mô tả nâng cao

Độ lệch (Skewness) và Độ nhọn (Kurtosis)

# Độ lệch (Skewness) - đo độ bất đối xứng
# > 0: lệch phải, < 0: lệch trái, = 0: đối xứng
skew = df['Doanh_thu'].skew()
print(f"Độ lệch: {skew:.2f}")

# Độ nhọn (Kurtosis) - đo độ nhọn của phân phối
# > 3: nhọn hơn phân phối chuẩn, < 3: phẳng hơn
kurtosis = df['Doanh_thu'].kurtosis()
print(f"Độ nhọn: {kurtosis:.2f}")

# Sử dụng scipy để tính chính xác hơn
from scipy import stats
skew_scipy = stats.skew(df['Doanh_thu'])
kurtosis_scipy = stats.kurtosis(df['Doanh_thu'])
print(f"Độ lệch (scipy): {skew_scipy:.2f}")
print(f"Độ nhọn (scipy): {kurtosis_scipy:.2f}")

Phân phối chuẩn hóa (Z-score)

# Tính Z-score (chuẩn hóa)
df['Doanh_thu_zscore'] = (df['Doanh_thu'] - df['Doanh_thu'].mean()) / df['Doanh_thu'].std()

# Hoặc sử dụng scipy
from scipy.stats import zscore
df['Doanh_thu_zscore2'] = zscore(df['Doanh_thu'])

# Tìm các giá trị ngoại lai (outliers) với Z-score > 3 hoặc < -3
outliers = df[abs(df['Doanh_thu_zscore']) > 3]
print(f"Số lượng giá trị ngoại lai: {len(outliers)}")
print(outliers[['Ngày', 'Doanh_thu', 'Doanh_thu_zscore']])

Tứ phân vị và Box Plot

# Tính tất cả các tứ phân vị
percentiles = [0, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0]
percentile_values = df['Doanh_thu'].quantile(percentiles)
print(percentile_values)

# Vẽ box plot để trực quan hóa
plt.figure(figsize=(10, 6))
df.boxplot(column='Doanh_thu', by='Khu_vực', figsize=(10, 6))
plt.title('Box Plot Doanh thu theo Khu vực')
plt.suptitle('')  # Xóa tiêu đề mặc định
plt.ylabel('Doanh thu')
plt.show()

Tương quan và Hiệp phương sai

# Ma trận tương quan
correlation_matrix = df[['Doanh_thu', 'Chi_phí', 'Lợi_nhuận', 'Số_lượng']].corr()
print(correlation_matrix)

# Tương quan giữa hai cột cụ thể
corr_revenue_profit = df['Doanh_thu'].corr(df['Lợi_nhuận'])
print(f"Tương quan Doanh thu - Lợi nhuận: {corr_revenue_profit:.2f}")

# Ma trận hiệp phương sai
covariance_matrix = df[['Doanh_thu', 'Chi_phí', 'Lợi_nhuận']].cov()
print(covariance_matrix)

# Vẽ heatmap tương quan
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0, 
            square=True, linewidths=1, cbar_kws={"shrink": 0.8})
plt.title('Ma trận Tương quan')
plt.tight_layout()
plt.show()

Thống kê theo thời gian

Khi làm việc với dữ liệu thời gian, bạn có thể tính thống kê theo các khoảng thời gian:

# Đặt Ngày làm index
df_time = df.set_index('Ngày')

# Thống kê theo tuần
weekly_stats = df_time['Doanh_thu'].resample('W').agg(['mean', 'sum', 'std'])
print(weekly_stats.head())

# Thống kê theo tháng
monthly_stats = df_time['Doanh_thu'].resample('M').agg(['mean', 'sum', 'std', 'min', 'max'])
print(monthly_stats)

# Thống kê theo quý
quarterly_stats = df_time['Doanh_thu'].resample('Q').agg(['mean', 'sum'])
print(quarterly_stats)

Ví dụ thực tế: Báo cáo thống kê hoàn chỉnh

Dưới đây là một ví dụ tạo báo cáo thống kê hoàn chỉnh:

def generate_statistics_report(df, numeric_columns):
    """
    Tạo báo cáo thống kê chi tiết cho các cột số
    """
    report = {}

    for col in numeric_columns:
        series = df[col]
        report[col] = {
            'Số lượng': series.count(),
            'Trung bình': series.mean(),
            'Trung vị': series.median(),
            'Độ lệch chuẩn': series.std(),
            'Phương sai': series.var(),
            'Min': series.min(),
            'Q1 (25%)': series.quantile(0.25),
            'Q2 (50%)': series.quantile(0.5),
            'Q3 (75%)': series.quantile(0.75),
            'Max': series.max(),
            'IQR': series.quantile(0.75) - series.quantile(0.25),
            'Range': series.max() - series.min(),
            'Độ lệch': series.skew(),
            'Độ nhọn': series.kurtosis(),
            'Hệ số biến thiên': series.std() / series.mean()
        }

    report_df = pd.DataFrame(report).T
    return report_df

# Tạo báo cáo
numeric_cols = ['Doanh_thu', 'Chi_phí', 'Lợi_nhuận', 'Số_lượng']
report = generate_statistics_report(df, numeric_cols)
print(report.round(2))

Trực quan hóa thống kê

# Vẽ histogram với thống kê
fig, axes = plt.subplots(2, 2, figsize=(15, 12))

# Histogram Doanh thu
axes[0, 0].hist(df['Doanh_thu'], bins=20, edgecolor='black', alpha=0.7)
axes[0, 0].axvline(df['Doanh_thu'].mean(), color='r', linestyle='--', label=f'Mean: {df["Doanh_thu"].mean():,.0f}')
axes[0, 0].axvline(df['Doanh_thu'].median(), color='g', linestyle='--', label=f'Median: {df["Doanh_thu"].median():,.0f}')
axes[0, 0].set_title('Phân phối Doanh thu')
axes[0, 0].set_xlabel('Doanh thu')
axes[0, 0].set_ylabel('Tần suất')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# Box plot theo Khu vực
df.boxplot(column='Doanh_thu', by='Khu_vực', ax=axes[0, 1])
axes[0, 1].set_title('Doanh thu theo Khu vực')
axes[0, 1].set_xlabel('Khu vực')
axes[0, 1].set_ylabel('Doanh thu')

# Scatter plot Doanh thu vs Lợi nhuận
axes[1, 0].scatter(df['Doanh_thu'], df['Lợi_nhuận'], alpha=0.6)
axes[1, 0].set_title('Tương quan Doanh thu - Lợi nhuận')
axes[1, 0].set_xlabel('Doanh thu')
axes[1, 0].set_ylabel('Lợi nhuận')
axes[1, 0].grid(True, alpha=0.3)

# Bar chart trung bình theo Khu vực
mean_by_region = df.groupby('Khu_vực')['Doanh_thu'].mean()
axes[1, 1].bar(mean_by_region.index, mean_by_region.values, color=['#1f77b4', '#ff7f0e', '#2ca02c'])
axes[1, 1].set_title('Trung bình Doanh thu theo Khu vực')
axes[1, 1].set_xlabel('Khu vực')
axes[1, 1].set_ylabel('Doanh thu trung bình')
axes[1, 1].grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()

Xử lý dữ liệu thiếu trong thống kê

# Tạo dữ liệu có giá trị thiếu
df_missing = df.copy()
df_missing.loc[df_missing.sample(10).index, 'Doanh_thu'] = np.nan

# Thống kê với dữ liệu thiếu
print("Số lượng giá trị thiếu:", df_missing['Doanh_thu'].isna().sum())
print("Thống kê (bỏ qua NaN):")
print(df_missing['Doanh_thu'].describe())

# Thống kê với skipna=False (sẽ trả về NaN nếu có giá trị thiếu)
mean_with_na = df_missing['Doanh_thu'].mean(skipna=False)
print(f"\nTrung bình (không bỏ qua NaN): {mean_with_na}")

# Điền giá trị thiếu trước khi tính thống kê
df_filled = df_missing.copy()
df_filled['Doanh_thu'].fillna(df_filled['Doanh_thu'].mean(), inplace=True)
print("\nThống kê sau khi điền giá trị thiếu:")
print(df_filled['Doanh_thu'].describe())

Kết luận

Thống kê lượng với DataFrame trong Python là một công cụ mạnh mẽ để phân tích và hiểu dữ liệu. Với Pandas, bạn có thể:

  • Tính toán các thống kê mô tả cơ bản và nâng cao
  • Phân tích dữ liệu theo nhóm
  • Trực quan hóa kết quả thống kê
  • Xử lý dữ liệu thiếu trong quá trình tính toán
  • Tạo báo cáo thống kê tự động

Để tìm hiểu thêm về Pandas, bạn có thể xem bài viết Giới thiệu về Pandas. Nếu bạn muốn áp dụng thống kê trong phân tích tài chính, hãy tham khảo bài viết Phân tích kỹ thuật với Python.

Tài liệu tham khảo