替换数字列中的除以符号
Replace divided by symbol in numeric column
我有一个包含以下内容的数据框:
df$old_price <- c('SR 2356' , 'SR 785' , 'SR 50/4 pack', 'SR 10/4 pack,'SR 490')
如何替换 old_price
列中的值,其中 'SR 50/4 pack' 或 'SR 10/4 包等值分别给出 12.5 和 2.5 而不会损坏数据?
我试过了df$old_price <- as.integer(gsub('[a-zA-Z]', '', df$old_price))
。但是,它似乎创建了奇怪的列值。
要获取带有除号 /
的字符的数值,另一种方法是拆分字符,以便提取不带 /
的数字。之后将提取出来的数字转为数值,然后用/
.
对数字进行除法
# Define the function
getNumber <- function(string_vect){
extracted_number <- gsub(".*?([0-9/0-9]+).*","\1", string_vect)
split_number <- strsplit(extracted_number, "/") |> unlist() |> as.numeric()
divided_number <- split_number[1]/split_number[2]
return(divided_number)
}
#Apply the function to the column
mydf <- data.frame(price = c("SR 50/4 pack", "SR 10/4"))
lapply(mydf$price, getNumber) |> unlist()
#[1] 12.5 2.5
如果该列包含混合字符,其中一些带有/
,而另一些则没有,可以使用条件if
和else
修改函数,如下所示:
getAllnumber <- function(string_vect){
extracted_number <- gsub(".*?([0-9/0-9]+).*","\1", string_vect)
if(grepl("/", string_vect)){
split_number <- strsplit(extracted_number, "/") |> unlist() |> as.numeric()
resulted_number <- split_number[1]/split_number[2]
}
else{
resulted_number <- extracted_number |> as.numeric()
}
return(resulted_number)
}
#apply the function to the column
mydf <- data.frame(price = c("SR 2356","SR 785","SR 50/4 pack",
"SR 10/4 pack","SR 490"))
lapply(mydf$price, getAllnumber) |> unlist()
#[1] 2356.0 785.0 12.5 2.5 490.0
# or
vapply(mydf$price, getAllnumber, numeric(1))
# SR 2356 SR 785 SR 50/4 pack SR 10/4 pack SR 490
# 2356.0 785.0 12.5 2.5 490.0
编辑以显示没有管道的相同函数
无需使用任何 |>
管道即可定义完全相同的函数,如下所示。
getAllnumber2 <- function(string_vect){
extracted_number <- gsub(".*?([0-9/0-9]+).*","\1", string_vect)
if(grepl("/", string_vect)){
split_number <- as.numeric(unlist(strsplit(extracted_number, "/")))
resulted_number <- split_number[1]/split_number[2]
}
else{
resulted_number <- as.numeric(extracted_number)
}
return(resulted_number)
}
mydf <- data.frame(price = c("SR 2356","SR 785","SR 50/4 pack",
"SR 10/4 pack","SR 490"))
unlist(lapply(mydf$price, getAllnumber2))
此代码将 return 与管道函数的结果相同:
#[1] 2356.0 785.0 12.5 2.5 490.0
不确定这有多稳定,但你可以试试
library(stringr)
library(dplyr)
df %>%
mutate(new.price = as.integer(str_extract(old.price, "\d+(?=/|$)")) / coalesce(as.integer(str_extract(old.price, "(?<=/)\d+")), 1))
这个returns
old.price new.price
1 SR 2356 2356.0
2 SR 785 785.0
3 SR 50/4 pack 12.5
4 SR 10/4 pack 2.5
5 SR 490 490.0
这可能是另一个解决方案:
library(stringr)
unlist(lapply(str_extract(vec, "\d.*\d"), \(x) eval(parse(text = x))))
[1] 2356.0 785.0 12.5 2.5 490.0
亲爱的 Ian Campbell:
建议的替代正则表达式解决方案
unlist(lapply(str_extract(vec, "[\d,./]+"), \(x) eval(parse(text = x))))
这是一个使用正则表达式与 stringr
中的 str_match
匹配的解决方案。
#sample data
input <- structure(list(item_id = 1:5,
price = c(265L, 995L, 20L, 7L, 421L),
old_price = c("105", "No old price", "SR 50/4 pack", "SR 10/4 pack", "520")),
class = "data.frame", row.names = c(NA, -5L))
# item_id price old_price
# 1 265 105
# 2 995 No old price
# 3 20 SR 50/4 pack
# 4 7 SR 10/4 pack
# 5 421 520
正则表达式在进行匹配时对每个值进行分组(例如 50
/4
)。然后我使用循环来识别匹配的记录并使用新值更新记录。
for(i in 1:nrow(input)) {
x <- as.numeric(str_match(input[i,]$old_price, "(\d+)\/(\d+)")[,2])
y <- as.numeric(str_match(input[i,]$old_price, "(\d+)\/(\d+)")[,3])
if(!is.na(x) && !is.na(y)) {
input[i,]$old_price <- x / y
}
}
# item_id price old_price
# 1 265 105
# 2 995 No old price
# 3 20 12.5
# 4 7 2.5
# 5 421 520
我有一个包含以下内容的数据框:
df$old_price <- c('SR 2356' , 'SR 785' , 'SR 50/4 pack', 'SR 10/4 pack,'SR 490')
如何替换 old_price
列中的值,其中 'SR 50/4 pack' 或 'SR 10/4 包等值分别给出 12.5 和 2.5 而不会损坏数据?
我试过了df$old_price <- as.integer(gsub('[a-zA-Z]', '', df$old_price))
。但是,它似乎创建了奇怪的列值。
要获取带有除号 /
的字符的数值,另一种方法是拆分字符,以便提取不带 /
的数字。之后将提取出来的数字转为数值,然后用/
.
# Define the function
getNumber <- function(string_vect){
extracted_number <- gsub(".*?([0-9/0-9]+).*","\1", string_vect)
split_number <- strsplit(extracted_number, "/") |> unlist() |> as.numeric()
divided_number <- split_number[1]/split_number[2]
return(divided_number)
}
#Apply the function to the column
mydf <- data.frame(price = c("SR 50/4 pack", "SR 10/4"))
lapply(mydf$price, getNumber) |> unlist()
#[1] 12.5 2.5
如果该列包含混合字符,其中一些带有/
,而另一些则没有,可以使用条件if
和else
修改函数,如下所示:
getAllnumber <- function(string_vect){
extracted_number <- gsub(".*?([0-9/0-9]+).*","\1", string_vect)
if(grepl("/", string_vect)){
split_number <- strsplit(extracted_number, "/") |> unlist() |> as.numeric()
resulted_number <- split_number[1]/split_number[2]
}
else{
resulted_number <- extracted_number |> as.numeric()
}
return(resulted_number)
}
#apply the function to the column
mydf <- data.frame(price = c("SR 2356","SR 785","SR 50/4 pack",
"SR 10/4 pack","SR 490"))
lapply(mydf$price, getAllnumber) |> unlist()
#[1] 2356.0 785.0 12.5 2.5 490.0
# or
vapply(mydf$price, getAllnumber, numeric(1))
# SR 2356 SR 785 SR 50/4 pack SR 10/4 pack SR 490
# 2356.0 785.0 12.5 2.5 490.0
编辑以显示没有管道的相同函数
无需使用任何 |>
管道即可定义完全相同的函数,如下所示。
getAllnumber2 <- function(string_vect){
extracted_number <- gsub(".*?([0-9/0-9]+).*","\1", string_vect)
if(grepl("/", string_vect)){
split_number <- as.numeric(unlist(strsplit(extracted_number, "/")))
resulted_number <- split_number[1]/split_number[2]
}
else{
resulted_number <- as.numeric(extracted_number)
}
return(resulted_number)
}
mydf <- data.frame(price = c("SR 2356","SR 785","SR 50/4 pack",
"SR 10/4 pack","SR 490"))
unlist(lapply(mydf$price, getAllnumber2))
此代码将 return 与管道函数的结果相同:
#[1] 2356.0 785.0 12.5 2.5 490.0
不确定这有多稳定,但你可以试试
library(stringr)
library(dplyr)
df %>%
mutate(new.price = as.integer(str_extract(old.price, "\d+(?=/|$)")) / coalesce(as.integer(str_extract(old.price, "(?<=/)\d+")), 1))
这个returns
old.price new.price
1 SR 2356 2356.0
2 SR 785 785.0
3 SR 50/4 pack 12.5
4 SR 10/4 pack 2.5
5 SR 490 490.0
这可能是另一个解决方案:
library(stringr)
unlist(lapply(str_extract(vec, "\d.*\d"), \(x) eval(parse(text = x))))
[1] 2356.0 785.0 12.5 2.5 490.0
亲爱的 Ian Campbell:
建议的替代正则表达式解决方案unlist(lapply(str_extract(vec, "[\d,./]+"), \(x) eval(parse(text = x))))
这是一个使用正则表达式与 stringr
中的 str_match
匹配的解决方案。
#sample data
input <- structure(list(item_id = 1:5,
price = c(265L, 995L, 20L, 7L, 421L),
old_price = c("105", "No old price", "SR 50/4 pack", "SR 10/4 pack", "520")),
class = "data.frame", row.names = c(NA, -5L))
# item_id price old_price
# 1 265 105
# 2 995 No old price
# 3 20 SR 50/4 pack
# 4 7 SR 10/4 pack
# 5 421 520
正则表达式在进行匹配时对每个值进行分组(例如 50
/4
)。然后我使用循环来识别匹配的记录并使用新值更新记录。
for(i in 1:nrow(input)) {
x <- as.numeric(str_match(input[i,]$old_price, "(\d+)\/(\d+)")[,2])
y <- as.numeric(str_match(input[i,]$old_price, "(\d+)\/(\d+)")[,3])
if(!is.na(x) && !is.na(y)) {
input[i,]$old_price <- x / y
}
}
# item_id price old_price
# 1 265 105
# 2 995 No old price
# 3 20 12.5
# 4 7 2.5
# 5 421 520