การวิเคราะห์หมากรุกด้วยข้อมูลที่ จำกัด


19

ในความท้าทายนี้คุณจะได้รับข้อมูลจำนวน จำกัด เกี่ยวกับเกมหมากรุกบางเกมและคุณต้องทำนายว่าใครจะชนะเกมนี้

คุณได้รับข้อมูลสองชุด:

  1. นับชิ้น (ชิ้นส่วนใดยังมีชีวิตอยู่)
  2. สีบอร์ด (สีของชิ้นส่วนบนกระดาน)

ที่สำคัญกว่าที่คุณไม่ทราบว่าชิ้นส่วนที่มีอยู่ คุณต้องตัดสินว่าใครที่คุณคิดว่าจะชนะ

เกมจะถูกเลือกจากกิจกรรมทั้งหมดที่ระบุไว้ในPGNMentorตั้งแต่ปี 2010 ถึงตอนนี้ ฉันได้เลือก 10% ของตำแหน่งกระดานทั้งหมดจากแต่ละเกมที่จบลงด้วยการชนะหรือแพ้ ตำแหน่งกรรมการจะต้องมีการเคลื่อนไหวอย่างน้อย 30 ครั้งในเกม กรณีทดสอบสามารถพบได้ที่นี่ (การชนะสีขาวแสดงรายการแรกตามด้วยการชนะสีดำ)

อินพุต

นับชิ้นจะเป็นสตริงที่ประกอบด้วยตัวอักษรสำหรับแต่ละชิ้น: kไอเอ็นจี, queen, rOOK, k night, bishop หรือpหนาม ตัวพิมพ์เล็กหมายถึงสีดำตัวพิมพ์ใหญ่เป็นสีขาว กระดานจะเป็นสตริง 64 ตัวอักษร (8 แถวคูณ 8 คอลัมน์) Bแทนชิ้นส่วนสีดำWแสดงชิ้นส่วนสีขาวและ.แทนจุดที่ว่างเปล่า ตัวอย่าง:

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

จะเป็นตัวแทนของคณะกรรมการดังต่อไปนี้

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

และที่ซึ่งทั้งสองสีนั้นมีบิชอป 2 ตัวกษัตริย์ 1 ตัวเบี้ย 7 ตัวพระราชินี 1 องค์ 2 แห่ง

เอาท์พุต

คุณจำเป็นต้องส่งกลับตัวเลขทศนิยมระหว่าง 0 ถึง 1 (รวม) เพื่อกำหนดว่าโอกาสที่สีขาวจะชนะนั้นเป็นอย่างไร ตัวอย่าง:

0.3     (30% chance that white wins)

รายละเอียดเพิ่มเติม:

  • แต่ละกรณีทดสอบมีค่า 1 คะแนน คะแนนของคุณจะเป็น1 - (1-Output)^2ถ้าสีขาวชนะหรือ1 - (Output)^2ถ้าสีดำชนะ
  • คะแนนสุดท้ายของคุณจะเป็นผลรวมของทุกกรณีทดสอบ
  • หากฉันรู้สึกว่าการส่งกำลังป้อนรหัสยากฉันขอสงวนสิทธิ์ในการเปลี่ยนแปลงกรณีทดสอบ (ถ้าฉันเปลี่ยนพวกเขาพวกเขาจะมีแฮช SHA-256 893be4425529f40bb9a0a7632f7a268a087ea00b0eb68293d6c599c6c671cdee)
  • โปรแกรมของคุณจะต้องเรียกใช้กรณีทดสอบอย่างอิสระ ไม่มีการบันทึกข้อมูลจากกรณีทดสอบหนึ่งไปยังอีกกรณี
  • ถ้าคุณกำลังใช้การเรียนรู้เครื่องผมขอแนะนำให้การฝึกอบรมในครั้งแรก 80% ของข้อมูลและทดสอบการใช้ส่วนที่เหลืออีก 20% (หรือเปอร์เซ็นต์ที่คุณใช้) ฉันใช้เกมหลายครั้งในข้อมูล แต่ฉันรวบรวมเกมเดียวกันเข้าด้วยกันตามลำดับ
  • ปรับปรุง:ฉันได้เพิ่มมากกว่าหนึ่งล้านกรณีทดสอบสำหรับวัตถุประสงค์ในการทดสอบและการเรียนรู้ พวกเขาถูกแบ่งออกเป็นชิ้นส่วนสีดำและสีขาวเนื่องจากข้อ จำกัด ขนาด repo GitHub

ขอให้โชคดีและสนุก!


การสนทนานี้ได้รับการย้ายไปแชท
Dennis

กรณีทดสอบใหม่ประกอบด้วยชุดทดสอบเก่าหรือทั้งสองชุดแยกกันหรือไม่
ทำให้เสียชีวิต

ฉันไม่รู้. ฉันได้รับจากเว็บไซต์ต่าง ๆ ดังนั้นจึงเป็นไปได้ว่าพวกเขาทั้งสองรวมเกมชุดเดียวกัน
Nathan Merrill

คำตอบ:


8

Java 8 + Weka, 6413 คะแนน, 94.5%

คำตอบนี้ใช้วิธีการเรียนรู้ของเครื่อง คุณจำเป็นต้องเรียกWekaห้องสมุดสะดุดตาและweka.jarPackageManager.jar

ที่นี่ฉันใช้ perceptron หลายชั้นเป็นลักษณนาม คุณสามารถแทนที่mlpด้วยClassifierWeka คลาสใดก็ได้เพื่อเปรียบเทียบผลลัพธ์

ฉันไม่ได้ปรับแต่งอะไรมากมายกับค่าพารามิเตอร์ของ MLP และเพียงแค่ทำให้ตาพวกเขา (ชั้นหนึ่งที่ซ่อนอยู่ของ 50 เซลล์ประสาท 100 ครั้งยุค 0.2 อัตราการเรียนรู้ 0.2 โมเมนตัม 0.1)

ฉันเกณฑ์มูลค่าส่งออกของ MLP ดังนั้นผลลัพธ์จริง ๆ อาจเป็น 1 หรือ 0 ตามที่กำหนดไว้ในความท้าทาย ด้วยวิธีนี้จำนวนของอินสแตนซ์ที่จำแนกอย่างถูกต้องตามที่พิมพ์โดย Weka นั้นเป็นคะแนนของเราโดยตรง

คุณสมบัติการก่อสร้างเวกเตอร์

ฉันเปลี่ยนแต่ละอินสแตนซ์จากสตริงเป็นเวกเตอร์ 76 องค์ประกอบโดยที่:

  • องค์ประกอบ 64 รายการแรกแสดงถึงเซลล์ของบอร์ดตามลำดับเดียวกับในสตริงโดยที่1ชิ้นส่วนสีขาว-1เป็นชิ้นส่วนสีดำและ0เป็นเซลล์ว่าง
  • องค์ประกอบ 12 ชิ้นสุดท้ายแสดงถึงแต่ละประเภทของชิ้นส่วน (6 ต่อผู้เล่น); ค่าขององค์ประกอบเหล่านั้นคือจำนวนชิ้นส่วนของประเภทนั้นบนกระดาน ( 0เป็น "ไม่มีชิ้นส่วนประเภทนั้น") เราสามารถใช้การปรับสภาพให้เป็นมาตรฐานเพื่อปรับเปลี่ยนค่าเหล่านั้นระหว่าง -1 และ 1 แต่นี่อาจไม่เป็นประโยชน์มากที่นี่

จำนวนอินสแตนซ์การฝึกอบรม

หากฉันใช้กรณีทดสอบทั้งหมดที่ได้รับการฝึกอบรมลักษณนามของฉันฉันมีการบริหารจัดการที่จะได้รับ6694 (คือ 98.6588%) กรณีจัดได้อย่างถูกต้อง เห็นได้ชัดว่าไม่น่าแปลกใจเลยที่การทดสอบแบบจำลองในข้อมูลเดียวกันกับที่คุณใช้ในการฝึกอบรมนั้นเป็นวิธีที่ง่ายเกินไป (เพราะในกรณีนี้มันดีจริง ๆ ที่แบบจำลองนั้นเหมาะสม

เมื่อใช้ชุดย่อยแบบสุ่ม 80% ของอินสแตนซ์เป็นข้อมูลการฝึกอบรมเราจะได้รับอินสแตนซ์ที่จำแนกประเภทอย่างถูกต้องที่รายงานในส่วนหัว (แน่นอนเนื่องจากชุดย่อยเป็นแบบสุ่มคุณอาจได้รับผลลัพธ์ที่แตกต่างกันเล็กน้อย) ฉันมั่นใจว่าตัวแบบจะทำงานได้ดีกับข้อมูลใหม่เนื่องจากการทดสอบในส่วนที่เหลืออีก 20% ของอินสแตนซ์ (ที่ไม่ได้ใช้สำหรับการฝึกอบรม) ให้การจำแนกประเภทที่ถูกต้อง77.0818%ซึ่งแสดงว่าแบบจำลองทั่วไปดีพอสมควร อินสแตนซ์ที่เราให้ไว้ที่นี่เป็นตัวแทนของกรณีทดสอบใหม่ที่เราจะได้รับ)

ใช้อินสแตนซ์ครึ่งหนึ่งสำหรับการฝึกอบรมและอีกครึ่งสำหรับการทดสอบเราได้รับ86.7502%สำหรับข้อมูลการฝึกอบรมและการทดสอบและ74.4988%สำหรับข้อมูลการทดสอบเท่านั้น

การดำเนินงาน

ดังที่ฉันได้กล่าวไปแล้วรหัสนี้ต้องใช้weka.jarและPackageManager.jarจาก Weka

TRAIN_PERCENTAGEหนึ่งสามารถควบคุมอัตราร้อยละของข้อมูลที่ใช้ในการฝึกอบรมชุดที่มี

พารามิเตอร์ของ MLP TRAIN_PERCENTAGEสามารถเปลี่ยนแปลงได้เพียงด้านล่าง เราสามารถลองตัวแยกประเภทอื่นของ Weka (เช่นSMOสำหรับ SVM) โดยเพียงแค่แทนที่mlpด้วยตัวจําแนกอื่น

โปรแกรมนี้พิมพ์ไปยังชุดผลลัพธ์โปรแกรมแรกที่อยู่ในทั้งชุด (รวมถึงข้อมูลที่ใช้สำหรับการฝึกอบรม) ซึ่งเป็นคะแนนตามที่กำหนดไว้ในการท้าทายนี้และโปรแกรมที่สองอยู่บนข้อมูลที่ไม่ได้ใช้สำหรับการฝึกอบรมเท่านั้น

อินพุตหนึ่งป้อนข้อมูลโดยส่งผ่านพา ธ ของไฟล์ที่มีมันเป็นอาร์กิวเมนต์ไปยังโปรแกรม

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;
    }
}

คุณเข้ารหัสอินพุตอย่างไร
Nathan Merrill

@NathanMerrill ฉันไม่แน่ใจว่าฉันเข้าใจคำถามของคุณแล้ว
Fatalize

คุณผ่านกรณีทดสอบเป็นอินพุตไปยังเครือข่ายประสาทได้อย่างไร คุณเพิ่งผ่านสายอักขระดิบหรือไม่
นาธานเมอร์ริลล์มี. ค.

@NathanMerrill แก้ไขด้วยย่อหน้าเกี่ยวกับการสร้างเวกเตอร์คุณสมบัติ
ทำให้เสียชีวิต

Weka รู้ได้อย่างไรว่าคุณกำลังพยายามทำนายผู้ชนะ
user1502040

8

GNU sed + bc, 4336 5074.5 คะแนน, 64 75%

อัปเดต: OP ให้วิธีใหม่ในการคำนวณคะแนนการทำนายสำหรับกรณีทดสอบแต่ละรายการ เมื่อใช้Wolfram Alphaฉันได้วางแผนสูตรทั้งสองชุดเพื่อดูความแตกต่าง

วิธีการในปัจจุบันนำมาซึ่งแรงจูงใจที่แข็งแกร่งในการส่งออกความน่าจะเป็นที่แท้จริงไม่ใช่เพียงแค่สุดขั้ว 0 และ 1 ซึ่งสูตรใหม่ให้คะแนนสูงสุดเท่าเดิม นี่คือเหตุผลที่อัลกอริทึมที่ไม่เปลี่ยนแปลงด้านล่างตอนนี้มีอัตราการทำนายที่ดีกว่าในความเป็นจริงอัตราที่ดีที่ให้ความเรียบง่าย

อย่างไรก็ตามยังมีข้อเสียเปรียบที่เกี่ยวข้องกับสูตรใหม่ดังที่อธิบายไว้ใน 'แก้ไข 1'


นี่คือการประมาณแบบง่าย ๆ โดยพิจารณาจากความได้เปรียบ / เสียเปรียบของวัสดุโดยไม่สนใจตำแหน่งที่แท้จริงของชิ้นงาน ฉันอยากรู้ว่าสิ่งนี้จะทำงานได้อย่างไร เหตุผลที่ฉันใช้ sed ไม่ใช่ภาษาที่สามารถทำได้ในหนึ่งบรรทัดเพราะมันเป็นภาษาลึกลับที่ฉันโปรดปราน

/:/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

ค่าชิ้นส่วนมาตรฐานที่ใช้:

  • 9 - ราชินี
  • 5 - โกง
  • 3 - อัศวิน
  • 3 - บิชอป
  • 1 - จำนำ
  • 0 - ราชา

ฉันคำนวณวัสดุสำหรับทั้งสองด้านและลบวัสดุของสีดำออกจากสีขาว เอาต์พุตสำหรับแต่ละกรณีทดสอบขึ้นอยู่กับความแตกต่างดังต่อไปนี้:

  • ถ้าความแตกต่าง> 0 ดังนั้นผลลัพธ์ = 1 (อาจชนะสีขาว)
  • ถ้า different = 0 ดังนั้น output = 0.5 (การวาดที่เป็นไปได้)

นี่คือผลลัพธ์บางส่วนของฉันเท่านั้นดังนั้นเหตุผลของการปรับปรุงตามที่อธิบายไว้ข้างต้น

  • หากความแตกต่าง <0 ดังนั้นผลลัพธ์ = 0 (อาจชนะสีดำ)

อัตราการทำนายสำหรับวิธีนี้คือ 64% ตอนนี้มันเป็น 75% กับสูตรใหม่

ตอนแรกฉันคาดว่ามันจะสูงกว่าพูด 70% แต่ในฐานะผู้เล่นหมากรุกตัวเองฉันสามารถเข้าใจผลได้เนื่องจากฉันแพ้หลายเกมตอนที่ฉันได้ +1 / +2 และชนะหลายครั้งเมื่อฉันลง วัสดุ. มันคือทั้งหมดที่เกี่ยวกับตำแหน่งที่แท้จริง (ดีตอนนี้ฉันได้รับความปรารถนาของฉัน!)

แก้ไข 1:ข้อเสียเปรียบ

วิธีแก้ปัญหาเล็ก ๆ น้อย ๆ คือการส่งออก 0.5 สำหรับแต่ละกรณีทดสอบเพราะวิธีนี้คุณได้คะแนนครึ่งจุดโดยไม่คำนึงถึงผู้ชนะ สำหรับกรณีทดสอบของเรานี่หมายถึงคะแนนรวม 3392.5 คะแนน (50%)

แต่ด้วยสูตรใหม่ 0.5 (ซึ่งเป็นผลลัพธ์ที่คุณให้ถ้าคุณไม่แน่ใจว่าใครชนะ) จะถูกแปลงเป็น 0.75 คะแนน โปรดจำไว้ว่าคะแนนสูงสุดที่คุณสามารถได้รับสำหรับกรณีทดสอบคือ 1 เพื่อความมั่นใจ 100% ในผู้ชนะ ดังนั้นคะแนนรวมใหม่สำหรับเอาต์พุต 0.5 คงที่คือ 5088.75 คะแนนหรือ 75%! ในความคิดของฉันแรงจูงใจที่แข็งแกร่งเกินไปสำหรับกรณีนี้

คะแนนนั้นดีกว่าแม้ว่าจะเล็กน้อยกว่าอัลกอริธึมตามความได้เปรียบด้านเนื้อหาของฉัน เหตุผลที่เป็นเพราะอัลกอริทึมให้ความน่าจะเป็น 1 หรือ 0 (ไม่มีแรงจูงใจ) สันนิษฐานว่าชนะหรือแพ้มากกว่าครั้งที่ (3831) มากกว่าที่จะให้ 0.5 (แรงจูงใจ) สันนิษฐานเสมอ (2954) วิธีการนี้เป็นวิธีที่ง่ายในท้ายที่สุดและเป็นเช่นนั้นไม่มีคำตอบที่ถูกต้องร้อยละที่สูง การเพิ่มจากสูตรใหม่ไปเป็นค่าคงที่ 0.5 จะช่วยให้สามารถเข้าถึงเปอร์เซ็นต์นั้นได้อย่างเทียม ๆ

แก้ไข 2:

มันเป็นความจริงที่รู้จักกันซึ่งถูกกล่าวถึงในหนังสือหมากรุกว่าโดยปกติแล้วจะดีกว่าถ้ามีคู่บิชอปมากกว่าคู่อัศวิน นี่เป็นเรื่องจริงโดยเฉพาะอย่างยิ่งในช่วงกลางถึงปลายของเกมโดยที่กรณีทดสอบเป็นเพราะมีแนวโน้มที่จะมีตำแหน่งเปิดที่มีช่วงของอธิการเพิ่มขึ้น

ดังนั้นฉันจึงทำการทดสอบครั้งที่สอง แต่คราวนี้ฉันเปลี่ยนค่าของบาทหลวงจาก 3 เป็น 3.5 คุณค่าของอัศวินยังคงอยู่ 3 นี่คือความชอบส่วนตัวดังนั้นฉันจึงไม่ได้ทำให้มันเป็นค่าเริ่มต้นของฉัน คะแนนรวมในกรณีนี้คือ 4411 คะแนน (65%) พบเพียงการเพิ่มจุด 1 เปอร์เซ็นต์

ด้วยสูตรใหม่ให้คะแนนรวม 4835 คะแนน (71%) ตอนนี้อธิการที่มีน้ำหนักต่ำกว่าที่ควรทำ แต่อธิบายถึงผลกระทบเนื่องจากวิธีการถ่วงน้ำหนักทำให้ได้รับชัยชนะหรือการสูญเสียมากขึ้น (5089) มากกว่าที่เสมอกัน (1696)


1
+1 สำหรับการให้บริการโซลูชันพื้นฐานที่สมเหตุสมผล ฉันยังสงสัยด้วยว่ามันจะทำงานได้ดีเพียงใด
Martin Ender

@MartinEnder ขอบคุณ ความคิดของฉันในการเพิ่มมูลค่าของอธิการซึ่งกล่าวถึงครั้งที่แล้วเพิ่มอัตราความสำเร็จเพียง 1% (ดูอัปเดต 2) ฉันคิดว่าค่ามาตรฐานได้รวมถึงผลกระทบนั้นหลังจากทั้งหมด
seshoumara

เฮ้ตามความคิดเห็นของ xnor คุณจะรังเกียจไหมถ้าฉันเปลี่ยนการให้คะแนนเป็นความแตกต่างสัมบูรณ์กำลังสอง?
นาธานเมอร์ริลล์

1
น่ากลัว นอกจากนี้ขอขอบคุณที่ตอบ! ฉันมักจะกังวลว่าคำถามที่ยากขึ้นของฉันจะไม่ได้รับคำตอบ
Nathan Merrill

@NathanMerrill ฉันได้อัปเดตคำตอบเพื่อใช้การให้คะแนนใหม่ตามที่ถาม ขออภัยสำหรับการวิเคราะห์ที่ยาวนาน แต่ฉันสงสัยจริงๆ
seshoumara

4

Python 3 - 84.6%, 5275 คะแนนในชุดการตรวจสอบความถูกต้อง

หากเราโกงและใช้ข้อมูลทั้งหมดเราสามารถบรรลุความแม่นยำ 99.3% และคะแนน 6408

เพียง MLP ขนาดใหญ่ที่ง่ายด้วยการออกกลางคันโดยใช้ 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)

คุณใช้ข้อมูลเท่าไหร่ในการฝึกอบรมเพื่อให้ได้ตัวเลข 84.6%
ทำให้เสียชีวิต

ฉันใช้การแบ่ง 90-10 ตามที่แสดงในรหัส
user1502040

เฮ้ฉันได้เพิ่มกรณีทดสอบอีกหลายตันถ้าคุณสนใจ
Nathan Merrill

2

Python 3 - ความแม่นยำ 94.3%, 6447 คะแนนในชุดการตรวจสอบความถูกต้องของข้อมูล 20%

ใช้เครือข่ายนิวรัล 3 แห่ง, เพื่อนบ้านที่ใกล้ที่สุด, ป่าสุ่มและการไล่ระดับสี การทำนายเหล่านี้จะถูกรวมเข้ากับฟอเรสต์แบบสุ่มซึ่งสามารถเข้าถึงข้อมูลได้

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))

เฮ้ฉันได้เพิ่มกรณีทดสอบอีกหลายตันถ้าคุณสนใจ
Nathan Merrill

ว้าวคุณออกไปบนนี้
Robert Fraser

สังเกตคำตอบจาวาที่นี่ว่า "beats" ของคุณดูเหมือนจะรายงาน% ในชุดข้อมูลทั้งหมดและจะได้รับ 77% จากข้อมูลที่ไม่ได้ทำการฝึกอบรม
Robert Fraser

0

Python 3 - 4353.25 / 6785 คะแนน - 64%

ดังนั้นเมื่อวานนี้ฉันทำงานเกี่ยวกับเรื่องนี้เป็นส่วนใหญ่ โพสต์แรกของฉันเล่นกอล์ฟและฉันเพิ่งใช้ python สัปดาห์หรือดังนั้นตอนนี้ดังนั้นยกโทษให้ฉันถ้าไม่ใช่ทุกอย่างปรับให้เหมาะสม

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

ฉันลงเอยด้วยเส้นทางเดียวกันกับคำตอบของ seshoumara เพื่อเริ่มต้น แต่กรณีทดสอบจำนวนมากที่มีจำนวนนับเหลืออยู่ทำให้ฉันไม่พอใจ

ดังนั้นฉันจึง googled ลักษณะที่บอกว่าใครเป็นผู้ชนะในหมากรุก นั่นคือสิ่งที่บิตนี้เข้ามา

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

ทั้งสองส่วนรวมกันจะใช้ในการหาคะแนน (0.0, 0.25, 0.50, 0.75, 1.0)

น่าสนใจมาก ๆ ที่บอร์ดนี้มีตำแหน่งพิเศษดูเหมือนจะไม่เพิ่มโอกาสในการเดาผู้ชนะ

หากคุณวางกรณีทดสอบลงในไฟล์บางไฟล์นี่คือการทดสอบ

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))

ฉันรู้ว่านี่ไม่ใช่ความท้าทายกอล์ฟ แต่คำแนะนำหรือคำแนะนำใด ๆ ในเรื่องนั้นได้รับการชื่นชม!


คำตอบของฉัน? คุณหมายถึงคำตอบของ seshoumara ใช่ไหม นอกจากนี้คุณไม่จำเป็นต้องเล่นกอล์ฟนี้ (เว้นแต่คุณต้องการ) นี่ไม่ใช่ความท้าทายสำหรับนักกอล์ฟ
นาธานเมอร์ริลล์

คุณสามารถบันทึกได้หลายไบต์โดยใช้ชื่อตัวแปรหนึ่งตัวเท่านั้น (แม้ว่ามันจะไม่สำคัญเพราะนี่ไม่ใช่โค้ดกอล์ฟ)
HyperNeutrino

woops! การแก้ไขที่ตอนนี้ ที่ทำงานนี่คือสิ่งที่ฉันได้รับจากการอ่าน skimming!
Datastream

2
กรุณาอย่าเล่นกอล์ฟ มันจะดีกว่าที่จะเก็บรหัสที่สามารถอ่านได้เมื่อมันไม่ใช่ code-golf
mbomb007

การควบคุมกลางกระดานไม่ได้หมายถึงการครอบครองกลางกระดาน แต่เป็นการโจมตีกลางกระดาน หากคุณต้องการเพิ่มความซับซ้อนรอบ ๆ มันอาจปรับปรุงคะแนนของคุณ
ไม่ใช่ชาร์ลส์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.