将分区文件夹列转换为变量
Posted
技术标签:
【中文标题】将分区文件夹列转换为变量【英文标题】:convert partitioning folder columns to variables 【发布时间】:2022-01-23 04:46:01 【问题描述】:我想像这样转换数据框:
mre <- tibble::tribble(
~folder3, ~folder2, ~folder1,
"V3=4", "V2=1", "V1=0",
"V3=5", "V2=1", "V1=0",
"V3=4", "V2=2", "V1=0",
"V3=5", "V2=2", "V1=0",
"V3=4", "V2=1", "V1=1",
"V3=5", "V2=1", "V1=1",
"V3=4", "V2=2", "V1=1",
"V3=5", "V2=2", "V1=1"
)
到这里:
folder3 folder2 folder1 V3 V2 V1
V3=4 V2=1 V1=0 4 1 0
V3=5 V2=1 V1=0 5 1 0
V3=4 V2=2 V1=0 4 2 0
V3=5 V2=2 V1=0 5 2 0
V3=4 V2=1 V1=1 4 1 1
V3=5 V2=1 V1=1 5 1 1
V3=4 V2=2 V1=1 4 2 1
V3=5 V2=2 V1=1 5 2 1
基本上为每个提取唯一变量名称(此处为“V3、“V2”、“V1”,但可以是任何有效名称,例如“a”、“b”、c”) folder?
列作为新列名,并将值保留在原位。
通过使用第一行值,我为单个“文件夹”列提供以下内容:
mre %>%
tidyr::extract(folder1, into = .$folder1[1] |> word(1, sep="="), "\\S+=(\\d+)", remove = FALSE)
但我不知道如何扩展到多个“文件夹”列(数量不固定)。我尝试在答案here 之后使用map
,但无法弄清楚如何从第一行获取变量名。
有什么建议吗?
【问题讨论】:
对不起,变量名“V3”在我的示例中与“folder3”重合。它可以是任意名称,因此需要从列值本身中提取。 【参考方案1】:代替extract
,我们可以在across
本身内创建新列-mutate
across
所有列(everything()
),使用str_extract
获取成功的数字(\\d+
) =
,同时将names
中的列名修改为str_replace
library(dplyr)
library(stringr)
mre %>%
mutate(across(everything(),
~ as.numeric(str_extract(., "(?<=\\=)\\d+")),
.names = "str_replace(.col, 'folder', 'V')"))
-输出
# A tibble: 8 × 6
folder3 folder2 folder1 V3 V2 V1
<chr> <chr> <chr> <dbl> <dbl> <dbl>
1 V3=4 V2=1 V1=0 4 1 0
2 V3=5 V2=1 V1=0 5 1 0
3 V3=4 V2=2 V1=0 4 2 0
4 V3=5 V2=2 V1=0 5 2 0
5 V3=4 V2=1 V1=1 4 1 1
6 V3=5 V2=1 V1=1 5 1 1
7 V3=4 V2=2 V1=1 4 2 1
8 V3=5 V2=2 V1=1 5 2 1
如果需要从“文件夹”列值中提取列名,则一种选择是使用pivot_longer
重塑为“长”,使用separate_rows
拆分列,使用@987654335 重塑回“宽” @并将列与原始数据绑定
library(tidyr)
mre %>%
mutate(rn = row_number()) %>%
pivot_longer(cols= starts_with('folder'), names_to = NULL) %>%
separate(value, into = c('name', 'value'), sep="\\=", convert = TRUE) %>%
pivot_wider(names_from = name, values_from = value) %>%
select(-rn) %>%
bind_cols(mre, .)
-输出
# A tibble: 8 × 6
folder3 folder2 folder1 V3 V2 V1
<chr> <chr> <chr> <int> <int> <int>
1 V3=4 V2=1 V1=0 4 1 0
2 V3=5 V2=1 V1=0 5 1 0
3 V3=4 V2=2 V1=0 4 2 0
4 V3=5 V2=2 V1=0 5 2 0
5 V3=4 V2=1 V1=1 4 1 1
6 V3=5 V2=1 V1=1 5 1 1
7 V3=4 V2=2 V1=1 4 2 1
8 V3=5 V2=2 V1=1 5 2 1
【讨论】:
str_extract
的优雅解决方案 :) 圣诞快乐,我的朋友!
@ThomasIsCoding 谢谢。也祝你圣诞快乐!
谢谢你的答案。不幸的是,变量名称并不总是像“V3”、“V2”、“V1”这样的规则。它们需要从列值中提取。
按照您的出色示例,以下工作从第一行中提取变量名称:mre %>% mutate(across(everything(), ~ as.numeric(str_remove(., "\\S+=")), .names = "str_sub(.[1,], 1, 2)"))
。但是,我无法使用更通用的正则表达式,例如 str_remove(.[1,], "=\\d+")
。在大括号中。
@akrun 使用行号的好技巧。【参考方案2】:
基本 R 选项
cbind(
mre,
unclass(
xtabs(
V2 ~ id + factor(V1, levels = unique(V1)),
do.call(
rbind,
Map(function(x) cbind(read.table(text = x, sep = "="), id = seq_along(x)), mre)
)
)
)
)
给予
folder3 folder2 folder1 V3 V2 V1
1 V3=4 V2=1 V1=0 4 1 0
2 V3=5 V2=1 V1=0 5 1 0
3 V3=4 V2=2 V1=0 4 2 0
4 V3=5 V2=2 V1=0 5 2 0
5 V3=4 V2=1 V1=1 4 1 1
6 V3=5 V2=1 V1=1 5 1 1
7 V3=4 V2=2 V1=1 4 2 1
8 V3=5 V2=2 V1=1 5 2 1
代码分解
Map(..., mre)
> Map(function(x) cbind(read.table(text = x, sep = "="), id = seq_along(x)), mre)
$folder3
V1 V2 id
1 V3 4 1
2 V3 5 2
3 V3 4 3
4 V3 5 4
5 V3 4 5
6 V3 5 6
7 V3 4 7
8 V3 5 8
$folder2
V1 V2 id
1 V2 1 1
2 V2 1 2
3 V2 2 3
4 V2 2 4
5 V2 1 5
6 V2 1 6
7 V2 2 7
8 V2 2 8
$folder1
V1 V2 id
1 V1 0 1
2 V1 0 2
3 V1 0 3
4 V1 0 4
5 V1 1 5
6 V1 1 6
7 V1 1 7
8 V1 1 8
do.call(rbind, ...)
> do.call(
+ rbind,
+ Map(function(x) cbind(read.table(text = x, sep = "="), id = seq_along(x)), mre)
+ )
V1 V2 id
folder3.1 V3 4 1
folder3.2 V3 5 2
folder3.3 V3 4 3
folder3.4 V3 5 4
folder3.5 V3 4 5
folder3.6 V3 5 6
folder3.7 V3 4 7
folder3.8 V3 5 8
folder2.1 V2 1 1
folder2.2 V2 1 2
folder2.3 V2 2 3
folder2.4 V2 2 4
folder2.5 V2 1 5
folder2.6 V2 1 6
folder2.7 V2 2 7
folder2.8 V2 2 8
folder1.1 V1 0 1
folder1.2 V1 0 2
folder1.3 V1 0 3
folder1.4 V1 0 4
folder1.5 V1 1 5
folder1.6 V1 1 6
folder1.7 V1 1 7
folder1.8 V1 1 8
xtabs(..., ...)
> xtabs(
+ V2 ~ id + factor(V1, levels = unique(V1)),
+ do.call(
+ rbind,
+ Map(function(x) cbind(read.table(text = x, sep = "="), id = se .... [TRUNCATED]
factor(V1, levels = unique(V1))
id V3 V2 V1
1 4 1 0
2 5 1 0
3 4 2 0
4 5 2 0
5 4 1 1
6 5 1 1
7 4 2 1
8 5 2 1
【讨论】:
或者另一个选项是mre[paste0("V", 3:1)] <- "dim<-"(as.numeric(sub(".*\\=", "", as.matrix(mre))), dim(mre))
@akrun 是的,该选项似乎比我的要短得多。谢谢:)
我觉得type.convert
会更容易理解mre[paste0("V", 3:1)] <- type.convert(sub(".*\\=", "", as.matrix(mre)), as.is = TRUE)
谢谢。这行得通。但这超出了我目前的理解范围。 :-(
@Dong 你可以看到我的代码故障【参考方案3】:
这是您可以使用的另一种解决方案:
library(dplyr)
library(stringr)
library(purrr)
mre %>%
bind_cols(
setNames(seq_len(ncol(mre)) %>%
map_dfc(~ y <- unname(unlist(mre[.x]))
as.integer(str_remove(y, "\\w+="))), paste0("V", 1:ncol(mre)))
)
# A tibble: 8 x 6
folder3 folder2 folder1 V1 V2 V3
<chr> <chr> <chr> <int> <int> <int>
1 V3=4 V2=1 V1=0 4 1 0
2 V3=5 V2=1 V1=0 5 1 0
3 V3=4 V2=2 V1=0 4 2 0
4 V3=5 V2=2 V1=0 5 2 0
5 V3=4 V2=1 V1=1 4 1 1
6 V3=5 V2=1 V1=1 5 1 1
7 V3=4 V2=2 V1=1 4 2 1
8 V3=5 V2=2 V1=1 5 2 1
【讨论】:
以上是关于将分区文件夹列转换为变量的主要内容,如果未能解决你的问题,请参考以下文章