我繼承了一張看起來有點像這樣的亂七八糟的桌子:
A1 B1 C1
V1 B1 0/1 C1 0/0 A1 1/1
V2 C1 0/1 A1 0/0 B1 0/1
V3 B1 0/0 NA A1 0/1
etc
實際上有更多的列和行
我想隨機排列每一行,使它們落在正確的列中,按名稱跨行匹配到特定列,但不垂直移動資料,僅水平移動,因為每一行都特定于 V 數。所需的輸出將是:
A1 B1 C1
V1 A1 1/1 B1 0/1 C1 0/0
V2 A1 0/0 B1 0/1 C1 0/1
V3 A1 0/1 B1 0/0 NA
如何在 R 中做到這一點?是指向真實資料子集的鏈接:
dput(t[1:5,21:27])
structure(list(`32-AA-0003` = c("32-PA-0002 0/1", "32-AA-0003 0/1",
"32-PA-0006 0/1", "32-GP-0001 0/1", "32-AA-0003 1/1"), `32-DA-0007` = c("",
"", "", "32-JA-0004 0/1", "32-DA-0007 1/1"), `32-GP-0001` = c("",
"", "", "32-PA-0002 0/1", "32-GP-0001 0/1"), `32-JA-0004` = c("",
"", "", "32-PA-0006 0/1", "32-JA-0004 0/1"), `32-MA-0005` = c("",
"", "", "", "32-MA-0005 1/1"), `32-PA-0002` = c("", "", "", "",
"32-PA-0002 0/1"), `32-PA-0006` = c("", "", "", "", "32-PA-0006 0/1"
)), row.names = c(NA, -5L), class = c("data.table", "data.frame"
), .internal.selfref = <pointer: 0x557151b3b940>)
非常感謝
uj5u.com熱心網友回復:
你可以做:
setNames(as.data.frame(t(apply(t, 1, function(x) {
sapply(names(t), function(y) {
z <- grep(y, x)
if(length(z) == 0) '' else x[z]
})
}))), names(t))
#> 32-AA-0003 32-DA-0007 32-GP-0001 32-JA-0004 32-MA-0005
#> 1
#> 2 32-AA-0003 0/1
#> 3
#> 4 32-GP-0001 0/1 32-JA-0004 0/1
#> 5 32-AA-0003 1/1 32-DA-0007 1/1 32-GP-0001 0/1 32-JA-0004 0/1 32-MA-0005 1/1
#> 32-PA-0002 32-PA-0006
#> 1 32-PA-0002 0/1
#> 2
#> 3 32-PA-0006 0/1
#> 4 32-PA-0002 0/1 32-PA-0006 0/1
#> 5 32-PA-0002 0/1 32-PA-0006 0/1
解釋
其作業方式如下。如果我們取資料框中的第一行,我們可以通過查看其中是否包含第一列的條目來找出哪些條目(如果有)屬于name第一列。我們用grep這個,所以我們可以做
grep(names(t)[1], t[1, ])
#> integer(0)
這告訴我們第一行中的任何字串都不應該在第一列中。由于我們想要一個空字串而不是一個integer(0)if 特定單元格沒有匹配項,因此我們需要將任何空匹配項轉換為 a ''。我們可以通過寫來做到這一點
z <- grep(names(t)[1], t[1, ])
if(length(z) == 0) '' else x[z]
如果有,則回傳匹配的字串,否則回傳空字串。
我們可以對每一列都這樣做,這樣我們就可以找出行中每個單元格屬于哪一列。我們可以把它寫成一個回圈:
result <- character(0)
for(i in 1:length(names(t))) {
z <- grep(names(t)[i], t[1, ])
result[i] <- if(length(z) == 0) '' else t[1, z]
}
result
#> [1] "" "" "" ""
#> [5] "" "32-PA-0002 0/1" ""
但在 R 中更簡潔的方法是使用sapply,這樣我們就不需要使用存盤向量 ( result),也不需要使用ito 索引:
sapply(names(t), function(y) {
z <- grep(y, t[1, ])
if(length(z) == 0) '' else t[1, z]
})
現在的問題是,這只給了我們資料框單行的結果,但我們想要每一行的結果。我們可以使用apply來指定我們想要一次傳遞一行,這意味著我們不需要單獨回圈遍歷每個t[1,]等t[2,]。我們只需要指定資料框t,以及我們想要操作的邊距(1,即逐行):
apply(t, 1, function(x) {
sapply(names(t), function(y) {
z <- grep(y, x)
if(length(z) == 0) '' else x[z]
})
})
#> [,1] [,2] [,3] [,4]
#> [1,] "" "32-AA-0003 0/1" "" ""
#> [2,] "" "" "" ""
#> [3,] "" "" "" "32-GP-0001 0/1"
#> [4,] "" "" "" "32-JA-0004 0/1"
#> [5,] "" "" "" ""
#> [6,] "32-PA-0002 0/1" "" "" "32-PA-0002 0/1"
#> [7,] "" "" "32-PA-0006 0/1" "32-PA-0006 0/1"
#> [,5]
#> [1,] "32-AA-0003 1/1"
#> [2,] "32-DA-0007 1/1"
#> [3,] "32-GP-0001 0/1"
#> [4,] "32-JA-0004 0/1"
#> [5,] "32-MA-0005 1/1"
#> [6,] "32-PA-0002 0/1"
#> [7,] "32-PA-0006 0/1"
現在我們有一個不同的問題,雖然我們有一個包含所有結果的矩陣,但它是轉置的。要反轉轉置,我們使用該函式t(這很令人困惑,因為您選擇t了資料框的名稱,因此這不是一個好主意)。最后,我們要使用 將轉置矩陣轉換為資料框as.data.frame,并使用setNames為該資料框賦予與原始資料框相同的名稱。所以最終的代碼是:
setNames(as.data.frame(t(apply(t, 1, function(x) {
sapply(names(t), function(y) {
z <- grep(y, x)
if(length(z) == 0) '' else x[z]
})
}))), names(t))
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/462126.html
上一篇:快速合并多個大型csv檔案
