范围字符串到单独的拆分

Range string to individual split

我有一个数据框 col 包含一系列成本中心值字符串。

A6652 - A6670

我想在下一个col中实现将它们拆分为

如何在 R 中实现?

一个简单的解决方案是:

# your data
df <- data.frame(costcentre.range = rep("A6652 - A6670", 19))

# solution
library(stringr) # required for `str_extract()`

df$individual <- paste0(
    "A", as.integer(str_extract(df$costcentre.range, "\d+")) + 0:(nrow(df)-1))

一个更复杂的解决方案,例如,如果 costcentre.range 并不总是以“A”开头,或者您有第二组范围,则可以如下所示:

# data with "A66##" and "B77##" individuals
df2 <- data.frame(
    costcentre.range = c(rep("A6651 - A6660", 10), rep("B7781 - B7790", 10)))

# solution
library(dplyr)
library(stringr)
library(tidyr)

df2 <- df2 %>% 
    mutate(first_id = str_extract(costcentre.range, "[A-Z]\d+")) %>% 
    separate(first_id, c("letter", "number"), "(?<=[A-Z])(?=\d+)", convert = TRUE) %>%
    group_by(costcentre.range) %>% 
    mutate(number = number + 0:(n()-1)) %>% 
    unite(individual, letter, number, sep = "")
df2

## A tibble: 20 x 2
## Groups:   costcentre.range [2]
#   costcentre.range individual
#   <fct>            <chr>     
# 1 A6651 - A6660    A6651     
# 2 A6651 - A6660    A6652     
# 3 A6651 - A6660    A6653     
# 4 A6651 - A6660    A6654     
# 5 A6651 - A6660    A6655     
# 6 A6651 - A6660    A6656     
# 7 A6651 - A6660    A6657     
# 8 A6651 - A6660    A6658     
# 9 A6651 - A6660    A6659     
#10 A6651 - A6660    A6660     
#11 B7781 - B7790    B7781     
#12 B7781 - B7790    B7782     
#13 B7781 - B7790    B7783     
#14 B7781 - B7790    B7784     
#15 B7781 - B7790    B7785     
#16 B7781 - B7790    B7786     
#17 B7781 - B7790    B7787     
#18 B7781 - B7790    B7788     
#19 B7781 - B7790    B7789     
#20 B7781 - B7790    B7790 

第一个目标是提取范围值 (str_extract()) 中的第一个 ID 字符串。
然后将字母值与数字值分开,以便您可以将数字值视为整数 (separate())、
然后您可以使用加法来更改数字 (mutate(number = ...))。
请注意,group_by(costcentre.range)n() 一起为您提供了 costcentre.range 中唯一值的组大小。
最后,再次将字母和新数字组合在一起,形成新列 (unite())。

使用来自@LC-datascientist post 的数据是一种tidyverse 方法。

只保留数据中的唯一行,将 costcentre.range 拆分为两列(startend),在它们之间创建一个序列并以长格式取消嵌套数据。

library(tidyverse)

df2 <- data.frame(
  costcentre.range = c(rep("A6651 - A6660", 10), rep("B7781 - B7790", 10)))

df2 %>%
  distinct() %>%
  separate(costcentre.range, c('start', 'end'), sep = '\s-\s') %>%
  mutate(group = sub('([A-Z]+).*', '\1', start),
         across(c(start, end), .fns = parse_number), 
         individual = map2(start, end, seq)) %>%
  unnest(individual) %>%
  unite(individual, group, individual, sep = '') %>%
  select(individual)

这个returns-

# individual
#   <chr>     
# 1 A6651     
# 2 A6652     
# 3 A6653     
# 4 A6654     
# 5 A6655     
# 6 A6656     
# 7 A6657     
# 8 A6658     
# 9 A6659     
#10 A6660     
#11 B7781     
#12 B7782     
#13 B7783     
#14 B7784     
#15 B7785     
#16 B7786     
#17 B7787     
#18 B7788     
#19 B7789     
#20 B7790