将分区文件夹列转换为变量

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本身内创建新列-mutateacross所有列(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 %&gt;% 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)] &lt;- "dim&lt;-"(as.numeric(sub(".*\\=", "", as.matrix(mre))), dim(mre)) @akrun 是的,该选项似乎比我的要短得多。谢谢:) 我觉得type.convert会更容易理解mre[paste0("V", 3:1)] &lt;- 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

【讨论】:

以上是关于将分区文件夹列转换为变量的主要内容,如果未能解决你的问题,请参考以下文章

将 CSV 列转换为列表

将多个分类变量转换为R中的因子

将 PubSub 流保存到 GCS 中的分区拼花文件

Hive UDF 全局变量

将逗号分隔字符串的熊猫列转换为虚拟变量

怎么将ISO文件转换成VHD文件呢··············