How do I extract data such as board configuration, engine evaluation, time spent per move etc from an engine into a statistical software package like stata? I am currently trying to investigate the effects of risk preferences on deviations from optimal play and know how to run statistical regression analysis but have no experience with chess datasets.

1 Answer 1


I am not sure about risk preferences, but here is an example that you can play around.

The features are the engine's best score, the human move score, etc. And the result could be your target.

There are only two positions as your dataset in this example. But you can extend this.

I use python chess library to create this system and use stockfish engine to analyze the positions.

import chess
import chess.engine
import pandas as pd

pd.set_option('display.max_colwidth', 1000)

# Positions and human move in the actual game.
FENS = [
    ['8/3b2pk/4qp1p/p2r4/1r1B1Q2/4P1P1/PP1R3P/K1R5 w - - 4 34', 'c1c7', '0-1'],
    ['r2q1rk1/ppp1nppp/1b6/3np3/6b1/1BPP1N1P/PP1N1PP1/R1BQ1RK1 b - - 0 12', 'g4h5', '1-0']

# Engine's path
STOCKFISH_PATH = r'F:\Chess\Engines\stockfish\sf16/sf16pop.exe'

def analyze_fen(fen, timesec=1.0, rootmoves=None):
    """Analyze the given fen position."""
    engine_hash_size = 128  # in MB
    engine_threads = 1      # number of threads
    board = chess.Board(fen)

    engine = chess.engine.SimpleEngine.popen_uci(STOCKFISH_PATH)
    engine.configure({"Hash": engine_hash_size, "Threads": engine_threads})
    info = engine.analyse(board, chess.engine.Limit(time=timesec), root_moves=rootmoves)

    best_move = info['pv'][0]
    score = info['score'].white().score(mate_score=32000)

    return best_move, score

def main():
    data = []
    analysis_timesec = 2.0

    for fen, human_move, result in FENS:
        # Get the best engine move and its score.
        engine_best_move, engine_best_score = analyze_fen(fen, timesec=analysis_timesec)

        # Get the score of the move by human.
        human_chess_move = chess.Move.from_uci(human_move)
        _, human_move_score = analyze_fen(fen, timesec=analysis_timesec, rootmoves=[human_chess_move])

        # Calculate the error.
        if engine_best_move == human_chess_move:
            error = 0
            error = abs(engine_best_score - human_move_score)
        data.append([fen, str(engine_best_move), engine_best_score, str(human_chess_move), human_move_score, result, error])

    df = pd.DataFrame(data, columns=['FEN', 'EMove', 'EScore', 'HMove', 'HScore', 'Result', 'Error'])

if __name__ == '__main__':


The scores are in WPOV (White Point of View), meaning if score is positive, the position assessment is better for white. If score is negative, it is better for black.

At index 0, the engine's best score is -24. It favors slightly for black. But the human move or the actual move played in the game is c1c7 and it is a blunder. The position assessment of that move is -504 CP or centipawn which put black in a winning position. The error is 480 which is just the absolute score difference.

                                                                   FEN EMove  EScore HMove  HScore Result  Error
0              8/3b2pk/4qp1p/p2r4/1r1B1Q2/4P1P1/PP1R3P/K1R5 w - - 4 34  f4c7     -24  c1c7    -504    0-1    480
1  r2q1rk1/ppp1nppp/1b6/3np3/6b1/1BPP1N1P/PP1N1PP1/R1BQ1RK1 b - - 0 12  g4f3      44  g4h5     128    1-0     84

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.