范围字符串到单独的拆分
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
拆分为两列(start
和 end
),在它们之间创建一个序列并以长格式取消嵌套数据。
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
我有一个数据框 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
拆分为两列(start
和 end
),在它们之间创建一个序列并以长格式取消嵌套数据。
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