Analisi degli scacchi con informazioni limitate


19

In questa sfida, ti viene data una quantità limitata di informazioni su una particolare partita di scacchi e devi pronosticare chi ha vinto la partita .

Ti vengono dati due set di dati:

  1. Il pezzo conta (Quali pezzi sono ancora vivi)
  2. Colori della tavola (il colore dei pezzi sulla tavola)

Ancora più importante, si non si sa dove si trovano i pezzi . Devi determinare chi pensi vincerà.

I giochi sono selezionati da tutti gli eventi elencati su PGNMentor dal 2010 a oggi. Ho selezionato il 10% di tutte le posizioni sul tabellone di ogni partita che termina con una vittoria o una perdita. Le posizioni sul tabellone saranno sempre almeno 30 mosse nel gioco. I casi di test sono disponibili qui . (Le vittorie bianche sono elencate per prime, seguite da quelle nere)

Ingresso

Il conteggio dei pezzi sarà una stringa composta da un personaggio per ogni pezzo: king, queen, ook r, k night, bishop o pawn. Minuscolo significa nero, maiuscolo è bianco. Il tabellone sarà una stringa di 64 caratteri (8 righe per 8 colonne). Brappresenta un pezzo nero, Wrappresenta un pezzo bianco e .rappresenta un punto vuoto. Campione:

W..WB......W.BB....W..B..W.WWBBB..W...B....W..BBWWW...BB.W....B.,BBKPPPPPPPQRRbbkpppppppqrr

rappresenterebbe la seguente scheda

...B.BB.
.BBBBBBB
.B.B....
B..W....
WWWW.W..
....W.W.
...W..WW
W.....W.

e dove entrambi i colori hanno 2 Vescovi, 1 Re, 7 Pedine, 1 Regina, 2 Corvi

Produzione

È necessario restituire un numero in virgola mobile compreso tra 0 e 1 (incluso) per determinare la probabilità che vince il bianco. Campione:

0.3     (30% chance that white wins)

Più dettagli:

  • Ogni caso di test vale 1 punto. Il tuo punteggio sarà 1 - (1-Output)^2se il bianco vince o 1 - (Output)^2se il nero vince.
  • Il tuo punteggio finale sarà la somma in tutti i casi di test.
  • Se ritengo che gli invii codifichino l'input, mi riservo il diritto di modificare i casi di test. (Se li cambio, avranno l'hash SHA-256 893be4425529f40bb9a0a7632f7a268a087ea00b0eb68293d6c599c6c671cdee)
  • Il programma deve eseguire casi di test in modo indipendente. Nessuna informazione di salvataggio da un caso di test al successivo.
  • Se stai utilizzando l'apprendimento automatico, ti consiglio vivamente di formare il primo 80% dei dati e di testare il restante 20% . (O qualunque percentuale tu usi). Uso i giochi più volte nei dati, ma ho unito gli stessi giochi in sequenza.
  • AGGIORNAMENTO: Ho aggiunto oltre un milione di casi di test a scopo di test e apprendimento. Sono divisi in parti in bianco e nero a causa dei limiti di dimensione repo github.

Buona fortuna e buon divertimento!


Questa conversazione è stata spostata in chat .
Dennis,

I nuovi casi di test contengono quelli vecchi o i due set sono disgiunti?
Fatalizza il

Non ne ho idea. Li ho presi da siti diversi, quindi è possibile che entrambi includessero lo stesso set di giochi.
Nathan Merrill,

Risposte:


8

Java 8 + Weka, 6413 punti, 94,5%

Questa risposta utilizza un approccio di apprendimento automatico. È necessario recuperare la libreria Weka , in particolare weka.jare PackageManager.jar.

Qui, uso un percettrone multistrato come classificatore; è possibile sostituire mlpcon qualsiasi Classifierclasse di Weka per confrontare i risultati.

Non ho armeggiato molto con i parametri della MLP e li ho semplicemente osservati (uno strato nascosto di 50 neuroni, 100 epoche, 0,2 velocità di apprendimento, 0,1 momentum).

Soglia il valore di output dell'MLP, quindi l'output è in realtà 1 o 0, come definito nella sfida. In questo modo il numero di istanze correttamente classificate come stampato da Weka è direttamente il nostro punteggio.

Costruzione vettoriale caratteristica

Trasformo ogni istanza da una stringa in un vettore di 76 elementi, dove:

  • I primi 64 elementi rappresentano le celle del tabellone, nello stesso ordine della stringa, dove 1è un pezzo bianco, -1è un pezzo nero ed 0è una cella vuota.
  • Gli ultimi 12 elementi rappresentano ogni tipo di pezzo (6 per giocatore); il valore di quegli elementi è il numero di pezzi di quel tipo sulla scacchiera ( 0essendo "nessun pezzo di quel tipo"). Si potrebbe applicare la normalizzazione per rimontare quei valori tra -1 e 1, ma probabilmente qui non è molto utile.

Numero di istanze di addestramento

Se utilizzo tutti i casi di test forniti per addestrare il mio classificatore, sono riuscito a ottenere 6694 (ovvero il 98,6588%) di istanze correttamente classificate . Questo ovviamente non sorprende perché testare un modello sugli stessi dati che hai usato per addestrarlo è troppo semplice (perché in quel caso è effettivamente buono che il modello si sovrapponga).

Usando un sottoinsieme casuale dell'80% delle istanze come dati di addestramento, otteniamo la cifra di istanze correttamente classificate 6413 (ovvero 94.5173%) riportate nell'intestazione (ovviamente poiché il sottoinsieme è casuale, si potrebbero ottenere risultati leggermente diversi). Sono fiducioso che il modello funzionerebbe decentemente bene sui nuovi dati, perché i test sul restante 20% delle istanze (che non sono stati utilizzati per la formazione) forniscono una classificazione corretta del 77,0818% , il che dimostra che i modelli si generalizzano decentemente bene (supponendo che il i casi che ci vengono forniti sono rappresentativi dei nuovi casi di test che ci verrebbero forniti).

Usando metà delle istanze per l'allenamento e l'altra metà per i test, otteniamo l' 86,7502% sui dati di allenamento e test e il 74,4988% solo sui dati di test.

Implementazione

Come ho già detto, questo codice richiede weka.jare PackageManager.jarda Weka.

Si può controllare la percentuale di dati utilizzati nel set di addestramento con TRAIN_PERCENTAGE.

I parametri dell'MLP possono essere modificati appena sotto TRAIN_PERCENTAGE. Si possono provare altri classificatori di Weka (ad es. SMOPer SVM) semplicemente sostituendoli mlpcon un altro classificatore.

Questo programma stampa su set di risultati, il primo è sull'intero set (compresi i dati utilizzati per l'allenamento) che è il punteggio definito in questa sfida, e il secondo è solo sui dati che non sono stati utilizzati per l'allenamento.

Uno immette i dati passando il percorso del file che lo contiene come argomento al programma.

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.functions.MultilayerPerceptron;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

public class Test {

    public static void main(String[] arg) {

        final double TRAIN_PERCENTAGE = 0.5;

        final String HIDDEN_LAYERS = "50";
        final int NB_EPOCHS = 100;
        final double LEARNING_RATE = 0.2;
        final double MOMENTUM = 0.1;

        Instances instances = parseInstances(arg[0]);
        instances.randomize(new java.util.Random(0));
        Instances trainingSet = new Instances(instances, 0, (int) Math.floor(instances.size() * TRAIN_PERCENTAGE));
        Instances testingSet = new Instances(instances, (int) Math.ceil(instances.size() * TRAIN_PERCENTAGE), (instances.size() - (int) Math.ceil(instances.size() * TRAIN_PERCENTAGE)));

        Classifier mlp = new MultilayerPerceptron();
        ((MultilayerPerceptron) mlp).setHiddenLayers(HIDDEN_LAYERS);
        ((MultilayerPerceptron) mlp).setTrainingTime(NB_EPOCHS);
        ((MultilayerPerceptron) mlp).setLearningRate(LEARNING_RATE);
        ((MultilayerPerceptron) mlp).setMomentum(MOMENTUM);


        try {
            // Training phase
            mlp.buildClassifier(trainingSet);
            // Test phase
            System.out.println("### CHALLENGE SCORE ###");
            Evaluation test = new Evaluation(trainingSet);
            test.evaluateModel(mlp, instances);
            System.out.println(test.toSummaryString());
            System.out.println();
            System.out.println("### TEST SET SCORE ###");
            Evaluation test2 = new Evaluation(trainingSet);
            test2.evaluateModel(mlp, testingSet);
            System.out.println(test2.toSummaryString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Instances parseInstances(String filePath) {
        ArrayList<Attribute> attrs = new ArrayList<>(); // Instances constructor only accepts ArrayList
        for(int i = 0 ; i < 76 ; i++) {
            attrs.add(new Attribute("a" + String.valueOf(i)));
        }
        attrs.add(new Attribute("winner", new ArrayList<String>(){{this.add("white");this.add("black");}}));
        Instances instances = new Instances("Rel", attrs, 10);
        instances.setClassIndex(76);

        try {
            BufferedReader r = new BufferedReader(new FileReader(filePath));
            String line;
            String winner = "white";
            while((line = r.readLine()) != null) {
                if(line.equals("White:")) {
                    winner = "white";
                } else if(line.equals("Black:")) {
                    winner = "black";
                } else {
                    Instance instance = new DenseInstance(77);
                    instance.setValue(attrs.get(76), winner);
                    String[] values = line.split(",");
                    for(int i = 0 ; i < values[0].length() ; i++) {
                        if(values[0].charAt(i) == 'B') {
                            instance.setValue(attrs.get(i), -1);
                        } else if(values[0].charAt(i) == 'W') {
                            instance.setValue(attrs.get(i), 1);
                        } else {
                            instance.setValue(attrs.get(i), 0);
                        }
                    }
                    // Ugly as hell
                    instance.setValue(attrs.get(64), values[1].length() - values[1].replace("k", "").length());
                    instance.setValue(attrs.get(65), values[1].length() - values[1].replace("q", "").length());
                    instance.setValue(attrs.get(66), values[1].length() - values[1].replace("r", "").length());
                    instance.setValue(attrs.get(67), values[1].length() - values[1].replace("n", "").length());
                    instance.setValue(attrs.get(68), values[1].length() - values[1].replace("b", "").length());
                    instance.setValue(attrs.get(69), values[1].length() - values[1].replace("p", "").length());
                    instance.setValue(attrs.get(70), values[1].length() - values[1].replace("K", "").length());
                    instance.setValue(attrs.get(71), values[1].length() - values[1].replace("Q", "").length());
                    instance.setValue(attrs.get(72), values[1].length() - values[1].replace("R", "").length());
                    instance.setValue(attrs.get(73), values[1].length() - values[1].replace("N", "").length());
                    instance.setValue(attrs.get(74), values[1].length() - values[1].replace("B", "").length());
                    instance.setValue(attrs.get(75), values[1].length() - values[1].replace("P", "").length());

                    instances.add(instance);
                }
            }
        } catch (Exception e) { // who cares
            e.printStackTrace();
        }
        return instances;
    }
}

Come si codifica l'input?
Nathan Merrill,

@NathanMerrill Non sono sicuro di aver capito la tua domanda
Fatalizza il

Come si passa il test case come input alla rete neurale? Stai solo passando la stringa non elaborata?
Nathan Merrill,

@NathanMerrill Modificato con un paragrafo sulla costruzione del vettore di feature.
Fatalizza il

Come fa Weka a sapere che stai cercando di prevedere il vincitore?
user1502040

8

GNU sed + bc, 4336 5074,5 punti, 64 75%

Aggiornamento: l'OP ha fornito un nuovo modo per calcolare il punteggio della previsione per un singolo caso di test. Usando Wolfram Alpha , ho tracciato entrambi i set di formule per vedere le differenze.

Il modo attuale porta un forte incentivo a produrre probabilità effettive e non solo gli estremi, 0 e 1, per i quali le nuove formule danno lo stesso punteggio massimo di prima. Questo è il motivo per cui l'algoritmo invariato di seguito ha ora un migliore tasso di previsione, in effetti un ottimo tasso data la sua semplicità.

Tuttavia, c'è anche uno svantaggio associato alle nuove formule, come spiegato in "Modifica 1".


Questa è una semplice stima basata solo sul vantaggio / svantaggio materiale, ignorando l'effettivo posizionamento dei pezzi. Ero curioso di sapere come funzionerà. Il motivo per cui uso sed, e non un linguaggio che può farlo in una riga, è perché è il mio linguaggio esoterico preferito.

/:/d                                             # delete the two headers
s:.*,::                                          # delete board positions
s:$:;Q9,R5,B3,N3,P1,K0,q-9,r-5,b-3,n-3,p-1,k-0:  # add relative piece value table
:r                                               # begin replacement loop
s:([a-Z])((.*)\1([^,]+)):\4+\2:                  # table lookup: letter-value repl.
tr                                               # repeat till last piece
s:;.*::                                          # delete value table
s:.*:echo '&0'|bc:e                              # get material difference: bc call
/^0$/c0.5                                        # print potential draw score
/-/c0                                            # print potential black win score
c1                                               # print potential white win score

Valori standard utilizzati:

  • 9 - Regina
  • 5 - Torre
  • 3 - Cavaliere
  • 3 - Vescovo
  • 1 - Pegno
  • 0 - Re

Calcolo il materiale per entrambi i lati e sottraggo il materiale nero da quello bianco. L'output per ciascun caso di test si basa su quella differenza come segue:

  • se differenza> 0, quindi output = 1 (potenziale vittoria bianca)
  • se differenza = 0, quindi output = 0,5 (potenziale disegno).

Questo è il mio unico risultato frazionato, quindi la ragione del miglioramento come spiegato sopra.

  • se differenza <0, quindi output = 0 (potenziale vittoria del nero)

Il tasso di predizione per questo metodo era del 64%. Ora è del 75% con le nuove formule.

Inizialmente mi aspettavo che fosse più alto, diciamo il 70%, ma come giocatore di scacchi me stesso posso capire il risultato, dal momento che ho perso così tante partite quando ero +1 / +2 e ne ho vinte tante quando ero giù Materiale. Riguarda la posizione attuale. (Bene, ora ho ricevuto il mio desiderio!)

Modifica 1: l'inconveniente

La banale soluzione è produrre 0,5 per ogni caso di test, perché in questo modo hai segnato mezzo punto indipendentemente da chi ha vinto. Per i nostri casi di test, ciò significava un punteggio totale di 3392,5 punti (50%).

Ma con le nuove formule, 0,5 (che è un risultato che daresti se sei indeciso su chi vince) viene convertito in 0,75 punti. Ricorda che il punteggio massimo che puoi ricevere per un caso di test è 1, per il 100% di fiducia nel vincitore. Pertanto, il nuovo punteggio totale per un output costante di 0,5 è 5088,75 punti, o 75%! Secondo me, l'incentivo è troppo forte per questo caso.

Quel punteggio è migliore, sebbene marginalmente, del mio algoritmo basato sul vantaggio materiale. Il motivo è che l'algoritmo dà una probabilità di 1 o 0 (nessun incentivo), presunte vincite o perdite, più volte (3831) rispetto a 0,5 (incentivo), pareggi previsti (2954). Il metodo è semplice alla fine e come tale non ha un'alta percentuale di risposte corrette. La spinta dalla nuova formula alla costante 0,5, riesce a raggiungere quella percentuale, artificialmente.

Modifica 2:

È un fatto noto, menzionato nei libri di scacchi, che di solito è meglio avere una coppia di vescovi piuttosto che una coppia di cavalieri. Ciò è particolarmente vero nella fase intermedia del gioco, in cui si trovano i casi di test, poiché è più probabile che abbia una posizione aperta in cui il raggio di un vescovo è aumentato.

Perciò ho fatto un secondo test, ma questa volta ho sostituito il valore dei vescovi da 3 a 3,5. Il valore del cavaliere è rimasto 3. Questa è una preferenza personale, quindi non l'ho resa la mia presentazione predefinita. Il punteggio totale in questo caso è stato di 4411 punti (65%). È stato osservato solo un aumento di 1 punto percentuale.

Con le nuove formule, il punteggio totale è di 4835 punti (71%). Ora il vescovo ponderato sottoperforma. Ma l'effetto è spiegato perché il metodo ponderato ora fornisce ancora più volte le vincite o le perdite presunte (5089), rispetto ai pareggi previsti (1696).


1
+1 per fornire una soluzione di base ragionevole. Mi chiedevo anche quanto bene avrebbe funzionato.
Martin Ender,

@MartinEnder Grazie. La mia idea di aumentare il valore del vescovo, menzionata l'ultima volta, ha prodotto solo un aumento del tasso di successo dell'1% (vedi Aggiornamento 2). Penso che i valori standard abbiano incluso quell'effetto dopo tutto.
seshoumara,

Ehi, secondo il commento di xnor, ti dispiacerebbe se cambio il punteggio in differenza assoluta al quadrato?
Nathan Merrill,

1
Eccezionale. Inoltre, grazie per aver risposto! Mi preoccupo sempre che le mie domande più difficili non avranno mai una risposta.
Nathan Merrill,

@NathanMerrill Ho aggiornato la mia risposta per utilizzare il nuovo punteggio come richiesto. Scusate la lunga analisi, ma ero davvero molto curioso.
seshoumara,

4

Python 3 - 84,6%, 5275 punti su un set di validazione

Se imbrogliamo e utilizziamo tutti i dati, possiamo ottenere una precisione del 99,3% e un punteggio di 6408

Solo un semplice MLP di grandi dimensioni con dropout usando Keras

import collections
import numpy as np
import random

import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.layers.noise import GaussianDropout
from keras.optimizers import Adam

np.random.seed(0)
random.seed(0)

def load_data():
    with open('test_cases.txt', 'r') as f:
        for line in f:
            yield line.split(',')

def parse_data(rows):
    black_pieces = "kpbkrq"
    white_pieces = black_pieces.upper()
    for i, row in enumerate(rows):
        if len(row) >= 2:
            board = row[0]
            board = np.array([1 if c == 'W' else -1 if c == 'B' else 0 for c in board], dtype=np.float32)
            pieces = row[1]
            counts = collections.Counter(pieces)
            white_counts = np.array([counts[c] for c in white_pieces], dtype=np.float32)
            black_counts = np.array([counts[c] for c in black_pieces], dtype=np.float32)
            yield (outcome, white_counts, black_counts, board)
        else:
            if 'White' in row[0]:
                outcome = 1
            else:
                outcome = 0

data = list(parse_data(load_data()))
random.shuffle(data)
data = list(zip(*data))
y = np.array(data[0])
x = list(zip(*data[1:]))
x = np.array([np.concatenate(xi) for xi in x])

i = len(y) // 10

x_test, x_train = x[:i], x[i:]
y_test, y_train = y[:i], y[i:]

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(76,)))
model.add(GaussianDropout(0.5))
model.add(Dense(512, activation='relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(512, activation='relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1, activation='sigmoid'))

model.compile(loss='mean_squared_error', optimizer=Adam())

use_all_data = False

x_valid, y_valid = x_test, y_test

if use_all_data:
    x_train, y_train = x_test, y_test = x, y
    validation_data=None
else:
    validation_data=(x_test, y_test)

batch_size = 128

history = model.fit(x_train, y_train, batch_size=batch_size, epochs=50, verbose=1, validation_data=validation_data)

y_pred = model.predict_on_batch(x_test).flatten()
y_class = np.round(y_pred)
print("accuracy: ", np.sum(y_class == y_test) / len(y_test))

score = np.sum((y_pred - (1 - y_test)) ** 2) * (len(y) / len(y_test))
print("score: ", score)

Quanti dati usi per allenarti per ottenere la cifra dell'84,6%?
Fatalizza il

Ho usato una divisione 90-10 come mostrato nel codice
user1502040

Ehi, ho aggiunto una tonnellata di più casi di test, se siete interessati.
Nathan Merrill,

2

Python 3 - Precisione del 94,3%, 6447 punti su un set di validazione del 20% dei dati

Utilizza 3 reti neurali, un regressore dei vicini più vicini, una foresta casuale e un potenziamento del gradiente. Queste previsioni sono combinate con una foresta casuale che ha anche accesso ai dati.

import collections
import numpy as np
import numpy.ma as ma
import random

import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, BatchNormalization, Activation, Conv2D, Flatten
from keras.layers.noise import GaussianDropout
from keras.callbacks import EarlyStopping
from keras.optimizers import Adam
from sklearn.neighbors import KNeighborsRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
import tensorflow

tensorflow.set_random_seed(1)
np.random.seed(1)
random.seed(1)

def load_data():
    with open('test_cases.txt', 'r') as f:
        for line in f:
            yield line.split(',')

def parse_data(rows):
    black_pieces = "kqrnbp"
    white_pieces = black_pieces.upper()
    for i, row in enumerate(rows):
        if len(row) >= 2:
            board = row[0]
            board = np.array([1 if c == 'W' else -1 if c == 'B' else 0 for c in board], dtype=np.float32)
            pieces = row[1]
            counts = collections.Counter(pieces)
            white_counts = np.array([counts[c] for c in white_pieces], dtype=np.float32)
            black_counts = np.array([counts[c] for c in black_pieces], dtype=np.float32)
            yield (outcome, white_counts, black_counts, board)
        else:
            if 'White' in row[0]:
                outcome = 1
            else:
                outcome = 0

data = list(parse_data(load_data()))
random.shuffle(data)
data = list(zip(*data))
y = np.array(data[0])
x = list(zip(*data[1:]))
conv_x = []
for white_counts, black_counts, board in x:
    board = board.reshape((1, 8, 8))
    white_board = board > 0
    black_board = board < 0
    counts = [white_counts, black_counts]
    for i, c in enumerate(counts):
        n = c.shape[0]
        counts[i] = np.tile(c, 64).reshape(n, 8, 8)
    features = np.concatenate([white_board, black_board] + counts, axis=0)
    conv_x.append(features)
conv_x = np.array(conv_x)
x = np.array([np.concatenate(xi) for xi in x])
s = x.std(axis=0)
u = x.mean(axis=0)
nz = s != 0
x = x[:,nz]
u = u[nz]
s = s[nz]
x = (x - u) / s

i = 2 * len(y) // 10

x_test, x_train = x[:i], x[i:]
conv_x_test, conv_x_train = conv_x[:i], conv_x[i:]
y_test, y_train = y[:i], y[i:]

model = Sequential()

def conv(n, w=3, shape=None):
    if shape is None:
        model.add(Conv2D(n, w, padding="same"))
    else:
        model.add(Conv2D(n, w, padding="same", input_shape=shape))
    model.add(BatchNormalization())
    model.add(Activation('relu'))

conv(128, shape=conv_x[0].shape) 
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(2, w=1)
model.add(Flatten())
model.add(GaussianDropout(0.5))
model.add(Dense(256))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1))
model.add(BatchNormalization())
model.add(Activation('sigmoid'))

model.compile(loss='mse', optimizer=Adam())

model5 = model

model = Sequential()
model.add(Dense(50, input_shape=(x.shape[1],)))
model.add(Activation('sigmoid'))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='mse', optimizer=Adam())

model0 = model

model = Sequential()
model.add(Dense(1024, input_shape=(x.shape[1],)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1024))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1024))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='mse', optimizer=Adam())

model4 = model

use_all_data = False

x_valid, y_valid = x_test, y_test

if use_all_data:
    x_train, y_train = x_test, y_test = x, y
    validation_data=None
else:
    validation_data=(x_test, y_test)

def subsample(x, y, p=0.9, keep_rest=False):
    m = np.random.binomial(1, p, size=len(y)).astype(np.bool)
    r = (x[m,:], y[m])
    if not keep_rest:
        return r
    m = ~m
    return r + (x[m,:], y[m])

epochs=100

x0, y0, x_valid, y_valid = subsample(conv_x_train, y_train, keep_rest=True)
model5.fit(x0, y0, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[EarlyStopping(patience=1)])

x0, y0, x_valid, y_valid = subsample(x_train, y_train, keep_rest=True)
model0.fit(x0, y0, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[EarlyStopping(patience=1)])

x0, y0, x_valid, y_valid = subsample(x_train, y_train, keep_rest=True)
model4.fit(x0, y0, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[EarlyStopping(patience=1)])

model1 = RandomForestRegressor(n_estimators=400, n_jobs=-1, verbose=1)
model1.fit(*subsample(x_train, y_train))

model2 = GradientBoostingRegressor(learning_rate=0.2, n_estimators=5000, verbose=1)
model2.fit(*subsample(x_train, y_train))

model3 = KNeighborsRegressor(n_neighbors=2, weights='distance', p=1)
model3.fit(*subsample(x_train, y_train))

models = (model0, model1, model2, model3, model4, model5)

model_names = [
    "shallow neural net",
    "random forest",
    "gradient boosting",
    "k-nearest neighbors",
    "deep neural net",
    "conv-net",
    "ensemble"
]

def combine(predictions):
    clip = lambda x: np.clip(x, 0, 1)
    return clip(np.array([y.flatten() for y in predictions]).T)

def augment(x, conv_x):
    p = combine([m.predict(x) for m in models[:-1]] + [models[-1].predict(conv_x)])
    return np.concatenate((x, p), axis=1)

model = RandomForestRegressor(n_estimators=200, n_jobs=-1, verbose=1)
model.fit(augment(x_train, conv_x_train), y_train)

def accuracy(prediction):
    class_prediction = np.where(prediction > 0.5, 1, 0)
    return np.sum(class_prediction == y_test) / len(y_test)

predictions = [m.predict(x_test).flatten() for m in models[:-1]] + [models[-1].predict(conv_x_test).flatten()]+ [model.predict(augment(x_test, conv_x_test))]

for s, p in zip(model_names, predictions):
    print(s + " accuracy: ", accuracy(p))

def evaluate(prediction):
    return np.sum(1 - (prediction - y_test) ** 2) * (len(y) / len(y_test))

for s, p in zip(model_names, predictions):
    print(s + " score: ", evaluate(p))

Ehi, ho aggiunto una tonnellata di più casi di test, se siete interessati.
Nathan Merrill,

Woah sei uscito per questo.
Robert Fraser,

Nota la risposta java qui che "batte" il tuo sembra riportare% sull'intero set di dati e ottiene solo il 77% sui dati con cui non si è allenato.
Robert Fraser,

0

Python 3 - 4353.25 / 6785 punti - 64%

Quindi ci ho lavorato soprattutto ieri. Il mio primo post golf, e ho usato Python solo una settimana o giù di lì, quindi perdonami se non tutto è ottimizzato.

def GetWhiteWinPercent(a):
finalWhiteWinPercent=0
i=a.index(',')

#position
board=a[:i]
blackBoardScore=0
whiteBoardScore=0
for r in range(i):
    if board[r] == 'B': blackBoardScore += abs(7 - (r % 8))
    if board[r] == 'W': whiteBoardScore += r % 8
if   whiteBoardScore > blackBoardScore: finalWhiteWinPercent += .5
elif whiteBoardScore < blackBoardScore: finalWhiteWinPercent += .0
else: finalWhiteWinPercent+=.25

#pieces
pieces=a[i:]
s = {'q':-9,'r':-5,'n':-3,'b':-3,'p':-1,'Q':9,'R':5,'N':3,'B':3,'P':1}
pieceScore = sum([s.get(z) for z in pieces if s.get(z) != None])
if   pieceScore < 0: finalWhiteWinPercent += 0
elif pieceScore > 0: finalWhiteWinPercent += .5
else: finalWhiteWinPercent += .25

return finalWhiteWinPercent

Ho finito per seguire lo stesso percorso della risposta di seshoumara per cominciare. Ma il gran numero di casi di test che avevano persino conteggi di pezzi mi ha lasciato insoddisfatto.

Quindi ho cercato su Google i tratti che determinano chi sta vincendo negli scacchi (non gioco io stesso) e ho notato che la posizione del tabellone, in particolare il controllo centrale, è grande. Ecco dove entra in gioco questo pezzo.

for r in range(i):
    if board[r] == 'B': blackBoardScore += abs(7 - (r % 8))
    if board[r] == 'W': whiteBoardScore += r % 8
if   whiteBoardScore > blackBoardScore: finalWhiteWinPercent += .5
elif whiteBoardScore < blackBoardScore: finalWhiteWinPercent += .0
else: finalWhiteWinPercent+=.25

Entrambe le metà combinate vengono utilizzate per trovare il punteggio (0,0, 0,25, 0,50, 0,75, 1,0)

Molto interessante il fatto che questo extra in classifica non sembri aumentare le possibilità di indovinare il vincitore.

Se lasci cadere i casi di test in alcuni file, ecco il test.

whiteWins=0
blackWins=0
totalWins=0
for line in open('testcases2.txt','r'):
    totalWins += 1
    blackWins += 1 - GetWhiteWinPercent(line)
for line in open('testcases.txt','r'):
    totalWins += 1
    whiteWins += GetWhiteWinPercent(line)

print(str(whiteWins+blackWins) +'/'+str(totalWins))

So che questa non è una sfida di golf, ma qualsiasi consiglio o consiglio in tal senso è apprezzato!


La mia risposta? Intendi la risposta di seshoumara? Inoltre, non è necessario giocare a golf (a meno che non lo si desideri). Questa non è una sfida di code-golf .
Nathan Merrill,

È possibile salvare molti byte utilizzando solo nomi di variabili di un carattere. (Anche se non importa davvero perché non si tratta di code-golf)
HyperNeutrino

Woops! Modificarlo ora. Al lavoro, questo è quello che ottengo per lo skimming!
Datastream

2
Per favore, non giocare a golf. È meglio mantenere il codice leggibile quando non è code-golf.
mbomb007

Il controllo del centro del tabellone non significa occupare il centro del tabellone, ma attaccare il centro del tabellone. Se volessi aggiungere un po 'di complessità, potresti migliorare il tuo punteggio.
Non che Charles
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.