import numpy as np
import pandas as pd
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler

class RandomSample:

    def __init__(self, X, y):
        self.scaler = StandardScaler()
        self.X = self.scaler.fit_transform(X)
        self.y = y
        self.model = LogisticRegression(solver='saga', max_iter=2000, tol=1e-3)
        self.unlabeled_X = list(range(len(self.X)))
        self.labeled_X = []

    def select(self):
        idx = np.random.randint(0, len(self.unlabeled_X))
        self.labeled_X.append(self.unlabeled_X[idx])
        del self.unlabeled_X[idx]

    def train(self, X_test, y_test):
        X_test_scaled = self.scaler.transform(X_test)
        n = len(self.unlabeled_X)
        for i in range(n):
            self.select()
            if len(self.labeled_X) < 2:
                continue
            self.model.fit(self.X[self.labeled_X], self.y[self.labeled_X])
            self.predict(X_test_scaled, y_test)

    def predict(self, X_test, y_test):
        y_pred = self.model.predict(X_test)
        acc = accuracy_score(y_test, y_pred)
        print(f"  样本数={len(self.labeled_X):>4}  准确率={acc:.4f}")

if __name__ == '__main__':
    df = pd.read_csv("datasets/Automobile.csv", header=None)
    X = df.iloc[:, :-1].to_numpy()
    y = df.iloc[:, -1].to_numpy()
    TEST_SIZE = 0.3
    UNLABELED_SIZE = 0.85  # 未标注池占非测试部分的比例,较大
    for split_i in range(20):
        print(f" 第 {split_i} 次循环")
        seed = 42 + split_i * 100
        rng = np.random.default_rng(seed)

        # 1) 分层抽测试集
        sss = StratifiedShuffleSplit(n_splits=1, test_size=TEST_SIZE, random_state=seed)
        rest_idx, test_idx = next(sss.split(X, y))
        y_rest = y[rest_idx]
        X_test , y_test = X[test_idx] , y[test_idx]

        # 2) 每个类别至少 1 个放入 labeled
        classes = np.unique(y_rest)
        one_per_class = [rng.choice(np.where(y_rest == c)[0], size=1)[0] for c in classes]

        # 3) 余下部分按比例抽 unlabeled,其余全归 labeled
        remaining = np.setdiff1d(np.arange(len(y_rest)), one_per_class) #生成剩余数组下标
        n_unlabeled = max(1, int(len(remaining) * UNLABELED_SIZE))
        unlabeled = rng.choice(remaining, size=n_unlabeled, replace=False)
        labeled = np.setdiff1d(np.arange(len(y_rest)), unlabeled)

        rs = RandomSample(X[rest_idx], y[rest_idx])
        rs.unlabeled_X = list(unlabeled)
        rs.labeled_X = list(labeled)
        rs.train(X_test, y_test)

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐