#r #dataframe #data-cleaning
#r #фрейм данных #очистка данных
Вопрос:
У меня есть R dataframe, в котором каждая ячейка настроена в следующем формате: number (число, число), следующим образом
#create dataframe as follows
x <- data.frame("Col1" = c("0.4646 (0.4061, 0.7522)", "0.4137 (0.0178, 0.617)"), "Col2"= c("0.1996 (0.1383, 0.3499)", "0.9814 (0.7092, 0.9884)"), stringsAsFactors = FALSE)
x[1,1]
#"0.4646 (0.4061, 0.7522)"
#I want 0.4646 to go in a column called "Col1est"
#0.4061 should go in a column called "Col1lower"
#0.7522 should go in a column called "Col1Upper"
Для каждой записи x я хочу разделить ее на 3 столбца. Запрос представлен в коде. Как мне извлечь конкретные значения из круглых скобок и поместить их в новые столбцы?
~ Генеральный директор
Ответ №1:
Вы можете попробовать этот подход, изменив данные на long и используя separate_rows()
для разделения значений. Здесь код:
library(tidyverse)
#Code
newx <- x %>% mutate(id=1:n()) %>%
pivot_longer(-id) %>%
separate_rows(value,sep = '\(') %>%
separate_rows(value,sep = ',') %>%
mutate(value=as.numeric(trimws(gsub(')','',value)))) %>%
group_by(id,name) %>%
mutate(name=ifelse(row_number()==1,paste0(name,'.est'),
ifelse(row_number()==2,paste0(name,'.low'),paste0(name,'.upper')))) %>%
pivot_wider(names_from = name,values_from=value) %>% ungroup() %>% select(-id)
Вывод:
# A tibble: 2 x 6
Col1.est Col1.low Col1.upper Col2.est Col2.low Col2.upper
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0.465 0.406 0.752 0.200 0.138 0.350
2 0.414 0.0178 0.617 0.981 0.709 0.988
Ответ №2:
Мы можем использовать map
для перебора имен столбцов и extract
столбца в разные столбцы
library(dplyr)
library(tidyr)
library(purrr)
library(stringr)
map_dfc(names(x), ~ x %>%
select(.x) %>%
extract(!!rlang::sym(.x),
into = str_c(.x, c('est', 'lower', 'Upper')),
'^([0-9.] )\s \(([0-9.] ),\s ([0-9.] )\).*', convert = TRUE) ) %>%
as_tibble
-вывод
# A tibble: 2 x 6
# Col1est Col1lower Col1Upper Col2est Col2lower Col2Upper
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#1 0.465 0.406 0.752 0.200 0.138 0.350
#2 0.414 0.0178 0.617 0.981 0.709 0.988
ПРИМЕЧАНИЕ: это возвращает правильный тип столбца
Или вариант с separate
x %>%
mutate(across(everything(), ~ str_remove_all(., '[(),]'))) %>%
separate(Col1, into = c('Col1est', 'Col1lower', 'Col1Upper'), sep=" ") %>%
separate(Col2, into = c('Col2est', 'Col2lower', 'Col2Upper'), sep=" ")
-вывод
# Col1est Col1lower Col1Upper Col2est Col2lower Col2Upper
#1 0.4646 0.4061 0.7522 0.1996 0.1383 0.3499
#2 0.4137 0.0178 0.617 0.9814 0.7092 0.9884
Или с помощью cSplit
from splitstackshape
library(data.table)
library(splitstackshape)
cSplit(setDT(x)[, lapply(.SD, gsub, pattern = '[(),]',
replacement = "")], c('Col1', 'Col2'), sep=" ")
-вывод
# Col1_1 Col1_2 Col1_3 Col2_1 Col2_2 Col2_3
#1: 0.4646 0.4061 0.7522 0.1996 0.1383 0.3499
#2: 0.4137 0.0178 0.6170 0.9814 0.7092 0.9884
Или используя base R
, мы можем использовать gsub
с read.table
f1 <- function(colval) {
read.table(text = gsub("[(),]", " ", colval), header = FALSE)
}
out <- do.call(cbind, lapply(x, f1))
names(out) <- paste0(sub("\..*", "", names(out)),
rep(c("est", "lower", "Upper"), 2))
-вывод
out
# Col1est Col1lower Col1Upper Col2est Col2lower Col2Upper
#1 0.4646 0.4061 0.7522 0.1996 0.1383 0.3499
#2 0.4137 0.0178 0.6170 0.9814 0.7092 0.9884
Ответ №3:
Получите данные в длинном формате, извлеките значения в отдельный столбец и получите данные обратно в широком формате.
library(dplyr)
library(tidyr)
x %>%
mutate(row = row_number()) %>%
pivot_longer(cols = -row) %>%
extract(value, c('est', 'lower', 'upper'), '(.*)\s\((.*),(.*)\)',
convert = TRUE) %>%
pivot_wider(names_from = name, values_from = est:upper,
names_glue = '{name}_{.value}') %>%
select(-row)
# Col1_est Col2_est Col1_lower Col2_lower Col1_upper Col2_upper
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#1 0.465 0.200 0.406 0.138 0.752 0.350
#2 0.414 0.981 0.0178 0.709 0.617 0.988
Ответ №4:
Для полноты картины, вот подход, который использует tstrsplit()
функцию from data.table
. Он работает без изменения формы / поворота для произвольного количества входных столбцов:
library(data.table)
library(magrittr) # piping used to improve readability
new_cols <- c("est", "lower", "upper")
setDT(x)[, lapply(.SD, function(x) tstrsplit(x, "[(),]")
%>% setDT() %>% setnames(new_cols))]
Col1.est Col1.lower Col1.upper Col2.est Col2.lower Col2.upper 1: 0.4646 0.4061 0.7522 0.1996 0.1383 0.3499 2: 0.4137 0.0178 0.617 0.9814 0.7092 0.9884
Выходные столбцы по-прежнему имеют тип character . В случае, если ожидаются числовые выходные столбцы, приведение может быть включено в канал:
setDT(x)[, lapply(.SD, function(x) tstrsplit(x, "[(),]") %>%
lapply(as.numeric) %>% setDT() %>% setnames(new_cols))]
Col1.est Col1.lower Col1.upper Col2.est Col2.lower Col2.upper 1: 0.4646 0.4061 0.7522 0.1996 0.1383 0.3499 2: 0.4137 0.0178 0.6170 0.9814 0.7092 0.9884