У меня есть таблица data.table с автоматически сгенерированными именами столбцов. Имена принимают форму:
Н.x.y.z
Где N — символ (буквально N), а остальные переменные — целые числа.
У меня также есть файл .csv, который связывает итерации x со значимыми строками. Как в:
Я хотел бы восстановить имена столбцов в формате:
Н.Имя.y.z
Я попытался сначала извлечь имена столбцов, например
thefile = fread('filepath')
xx <- colnames(thefile)
colindex <- read.csv('the other file path')
colindex[,1] <- paste0('N.', colindex[,1], '.') #Converting x to N.x.
Я возился с grepl, replace_at, разделяя строку на '.'
read.table(text = "X Name
1 Model
3 Mileage",
header = T, stringsAsFactor = FALSE) -> colindex
df1 <- data.frame(`N.1.2.3` = c(1,2), `N.3.1.2` = c(6,5),
`N.1.3.1` = c(3, 4), `N.3.2.2` = c(8, 7))
df1
#> N.1.2.3 N.3.1.2 N.1.3.1 N.3.2.2
#> 1 1 6 3 8
#> 2 2 5 4 7
names_split <- as.data.frame(strsplit(names(df1), "\\."))
names_split[2,] <- colindex[match(names_split[2,], colindex$X), "Name"]
names(df1) <- apply(names_split, 2, paste, collapse = ".")
df1
#> N.Model.2.3 N.Mileage.1.2 N.Model.3.1 N.Mileage.2.2
#> 1 1 6 3 8
#> 2 2 5 4 7
Created on 2024-03-18 with reprex v2.0.2
Другой вариант (с использованием данных @M--) — использовать stringr
:
stringr::str_replace_all(
names(df1),
setNames(paste0("N.", colindex$Name), paste0("N\\.", colindex$X)))
# [1] "N.Model.2.3" "N.Mileage.1.2" "N.Model.3.1" "N.Mileage.2.2"
(и переназначить их обратно с помощью names(df1) <-
)
Этот подход немного специфичен: то, что вы хотите, должно быть точно рядом с буквальным N.
. При необходимости его можно адаптировать к другим положениям, слегка изменив рисунок.
Версия base-R может быть:
gre <- gregexpr("(?<=N[.])([0-9]+)(?=[.])", names(df1), perl = TRUE)
regmatches(names(df1), gre) <- colindex$Name[match(unlist(regmatches(names(df1), gre)), colindex$X)]
df1
# N.Model.2.3 N.Mileage.1.2 N.Model.3.1 N.Mileage.2.2
# 1 1 6 3 8
# 2 2 5 4 7
Спасибо за решение. Могу ли я задать косвенный вопрос; насколько важно регулярное выражение для R? Это не то, что мне приходилось использовать перед использованием конкретного приложения Matlab.
Выполняет ли Matlab динамическую модификацию строк с помощью какого-либо другого типа выражения? Regex — это отдельный язык/конструкция, определенно не уникальная для R. Как и другие конструкции, она очень эффективна для многих вещей и неправильно используется в других.
Возможно, но мне не приходилось его использовать, я в основном выполнял вычисления с массивами, поэтому мне никогда не приходилось делать что-то сложное со строками. Поскольку я собираюсь больше использовать R для задач, в которых используются как числовые, так и текстовые данные, мне интересно, поможет ли знакомство с регулярными выражениями или это будет полезно лишь изредка.
Как я уже сказал, регулярное выражение — это инструмент, который нужно использовать. Это не специфично для R... видимо, matlab тоже делает регулярное выражение . Некоторые вещи Regex делает очень хорошо, а для других он вообще не подходит (например, не парсинг HTML). Мир регулярных выражений может быть волшебным, и при правильном использовании он великолепен, но в некоторых ситуациях он не самый лучший (производительность, стабильность и т.д.). Я не говорю, что регулярное выражение — это волшебный эликсир, просто его можно безопасно использовать.
Используя data.table::setnames
, разделите имена столбцов на "."
, затем вставьте их обратно, заменив второй элемент из поиска:
library(data.table)
lookup <- fread(text = "X Name
1 Model
3 Mileage",
header = T, stringsAsFactor = FALSE)
# convert to named vector
lookup <- setNames(lookup$Name, lookup$X)
dt <- data.table(`N.1.2.3` = c(1,2), `N.3.1.2` = c(6,5),
`N.1.3.1` = c(3, 4), `N.3.2.2` = c(8, 7))
setnames(dt,
new = sapply(strsplit(colnames(dt), ".", fixed = TRUE), function(i){
paste(i[ 1 ], lookup[ i[ 2 ] ], i[ 3 ], i[ 4 ], sep = ".") } ))
dt
# N.Model.2.3 N.Mileage.1.2 N.Model.3.1 N.Mileage.2.2
# <num> <num> <num> <num>
# 1: 1 6 3 8
# 2: 2 5 4 7
library(tidyverse)
rename_with(df1, ~str_replace(.x, "\\d", ~deframe(colindex)[.x]))
N.Model.2.3 N.Mileage.1.2 N.Model.3.1 N.Mileage.2.2
1 1 6 3 8
2 2 5 4 7
Другие варианты:
rename_with(df1,~str_replace_all(.x,deframe(map(colindex, ~str_c('N.', .x)))))
N.Model.2.3 N.Mileage.1.2 N.Model.3.1 N.Mileage.2.2
1 1 6 3 8
2 2 5 4 7
база Р:
fn <- \(x,y)sub(sprintf("(?<=N.)%s", y[1]), y[2], x, perl = TRUE)
setNames(df1, Reduce(fn, asplit(colindex, 1), names(df1)))
N.Model.2.3 N.Mileage.1.2 N.Model.3.1 N.Mileage.2.2
1 1 6 3 8
2 2 5 4 7
Данные:
colindex <- read.table(text = "X Name
1 Model
3 Mileage",
header = T, stringsAsFactor = FALSE)
df1 <- data.frame(`N.1.2.3` = c(1,2), `N.3.1.2` = c(6,5),
`N.1.3.1` = c(3, 4), `N.3.2.2` = c(8, 7))
Да, это работает, спасибо. Вероятно, я неправильно прочитал документацию, но мне кажется, что match найдет первый экземпляр совпадения, а не все экземпляры, но здесь он находит все экземпляры.