我有一个象棋游戏的数据框,有两列,如下所示
dd <- data.frame(
game_id = c(101,102),
moves = c("1.e4 c5 2.Nf3 d6 3.d4 cxd4 4.Nxd4 Nf6 5.Nc3 Nc6 6.Bc4 e6 7.Be3 Be7","1.e3 c5 2.Nf3 Nc6 3.d4 cxd4 4.Nxd4 Nf6 5.Nc3 e5 6.Ndb5 d6")
)
这里的每一行都是一个单独的游戏,由游戏 ID 唯一标识。移动列按从左到右的顺序包含游戏的所有移动。移动的序列号可以通过每个点“.”之前的数字来识别。每一步都有两个部分;第一部分始终是白棋手的棋步,第二步是黑棋棋手的棋步。这两个部分由一个空格隔开。如上数据所示,连续的两步棋也用一个空格隔开,但是,序号的点与白棋棋步的第一个字符之间没有间隙。游戏中的总步数是任意的,因为有些游戏以几步结束,而另一些则可能有许多步。
问题:正如我们所见,游戏的所有 Action 都存在于数据框的一个单元格中,这不太容易分析。我想将其转换为具有更好结构的数据框,如下所示:
game_id | move_no | white | black
----------------------------------
101 | 1 | e4 | c5
101 | 2 | Nf3 | d6
101 | 3 | d4 | cxd4
101 | 4 | Nxd4 | Nf6
如何在 R 中做到这一点?
最佳答案
我们可以使用正则表达式来绘制移动字符串。这里我使用 stringr::str_match_all
来捕捉 Action 的每个部分。
dd$moves |>
stringr::str_match_all(r"{(\d+)\.(\S+) (\S+)}") |>
lapply(function(x) data.frame(move_id=as.numeric(x[,2]), white=x[,3], black=x[,4])) |>
Map(cbind.data.frame, game_id=dd$game_id, m=_) |>
do.call("rbind", args=_)
将返回
game_id m.move_id m.white m.black
1 101 1 e4 c5
2 101 2 Nf3 d6
3 101 3 d4 cxd4
4 101 4 Nxd4 Nf6
5 101 5 Nc3 Nc6
6 101 6 Bc4 e6
7 101 7 Be3 Be7
8 102 1 e3 c5
9 102 2 Nf3 Nc6
主要部分是正则表达式 r"{(\d+)\.(\S+) (\S+)}"
它找到一个数字后跟一个句点,然后尝试找到两个不包含空格的乐曲名称,它们之间有空格。
关于r - 如何将一串连续的国际象棋移动转换为垂直数据框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72637786/