我有一個包含兩列的國際象棋游戲資料框,如下所示
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 唯一標識。移動列按從左到右的順序包含游戲的所有移動。移動的序列號可以通過每個點“.”之前的數字來識別。每一步都有兩個部分;第一部分始終是白棋手的棋步,第二步是黑棋棋手的棋步。這兩個部分由一個空格隔開。如上資料所示,連續的兩步棋也用一個空格隔開,但是,序號的點與白棋棋步的第一個字符之間沒有間隙。游戲中的移動總數是任意的,因為一些游戲以幾個移動結束,而另一些可能有很多移動。
問題:正如我們所見,游戲的所有動作都存在于資料幀的一個單元格中,這不太容易分析。我想將其轉換為具有更好結構的資料框,如下所示:
game_id | move_no | white | black
----------------------------------
101 | 1 | e4 | c5
101 | 2 | Nf3 | d6
101 | 3 | d4 | cxd4
101 | 4 | Nxd4 | Nf6
如何在 R 中做到這一點?
uj5u.com熱心網友回復:
我們可以使用正則運算式對移動字串進行 splot。在這里,我習慣于stringr::str_match_all捕捉動作的每個部分。
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 )}",它找到一個數字后跟一個句點,然后嘗試找到兩個不包含空格的片段名稱,它們之間有一個空格。
uj5u.com熱心網友回復:
這是使用 stringr、dplyr 和 tidyr 庫的一個非常不雅的答案。
首先,我們使用 stringr 中的 str_split_fixed 將每次移動的字符向量拆分為 data.frame。然后我們將這些列附加到現有的 data.frame 中。
接下來我們使用 dplyr 和 tidyr 重塑資料。首先,我們將“移動”列從寬格式資料轉換為長格式資料。然后我們通過上面給出的順序來推斷“移動”的顏色,以及移動列的數量來推斷移動的數量。
然后我們按顏色旋轉新創建的運動資料。從那里,我們修改記錄的移動,以便一個“移動”對應一個“轉”(也就是每種顏色的移動)。然后我們按移動編號和游戲型別分組,并從我們的樞軸中清理剩余的空列。
不是世界上最優雅的答案,但它有效嗎?
#load libs
library(stringr)
library(dplyr)
library(tidyr)
#create sample data
chess = data.frame(
game_id = c(101,102),
moves = c("1.e4 2Nf3 d6 Nf6","1.e3 2Nf4 nc6 cxd4")
)
#split characters vectors to columns
moves = data.frame(str_split_fixed(chess$moves," ",Inf)) #returns a matrix by default so coerce to data.frame to make binding easier
chess = bind_cols(chess,moves) #bind the new data
#melt the data into long form
chess %>%
select(game_id,X1:X4) %>% #here we avoid selecting the default col we don't need
pivot_longer(cols = X1:X4,names_to="move_no") %>% #melt/pivot split columns to one column
mutate(color = rep(c("white","black"),ncol(chess)-2)) %>% #infer color by every other move, infer length by n of movement columns
pivot_wider(names_from=color,values_from=value) %>% #pivot moves by color wider
mutate(move_no = sort(rep(c(1:(ncol(chess)-2)),2))) %>% #update move_no colum to be accurate, note we use sort to get the needed order of moves
group_by(game_id,move_no) %>%
summarise(
white = last(na.omit(white)), #last will return the last non NA value, getting us to a valid data.frame
black = last(na.omit(black))
)
uj5u.com熱心網友回復:
以R為底
資料
x <- "
game_id | moves
101 | 1.e4 c5 2.Nf3 d6 3.d4 cxd4 4.Nxd4 Nf6 5.Nc3 Nc6 6.Bc4 e6 7.Be3 Be7
102 | 1.e3 c5 2.Nf3 Nc6 3.d4 cxd4 4.Nxd4 Nf6 5.Nc3 e5 6.Ndb5 d6
"
df <- read.table(textConnection(x) , header = T , sep = "|")
使用fn功能
fn <- function(df) {
lst <- list()
id <- 1 ; L <- 1
clmn <- strsplit(trimws(df$moves) , "[. ]")
for (i in clmn) {
for (j in 1:(length(i) / 3)) {
j <- 3*j - 2
lst[[id]] <- c(df$game_id[[L]] , clmn[[L]][j:(j 2)])
id <- id 1
}
L <- L 1
}
lst
}
#===================================
df <- data.frame(do.call(rbind , fn(df)))
colnames(df) <- c("game_id" , "move_no" , "white" , "black")
輸出
df
#> game_id move_no white 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
#> 10 102 3 d4 cxd4
#> 11 102 4 Nxd4 Nf6
#> 12 102 5 Nc3 e5
#> 13 102 6 Ndb5 d6
由reprex 包于 2022-06-16 創建(v2.0.1)
uj5u.com熱心網友回復:
dd <- tibble(
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"
)
)
pattern <- r"{(\d )\.(\S ) (\S )}"
dd |>
mutate(moves = str_extract_all(moves, pattern)) |>
unnest(moves) |>
mutate(
move_no = str_replace(moves, pattern, "\\1"),
white = str_replace(moves, pattern, "\\2"),
black = str_replace(moves, pattern, "\\3")
) |>
select(-moves)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/491549.html
上一篇:將帶分隔符的字串拆分為虛擬變數
