У меня есть фрейм данных со столбцом символов. Я пытаюсь поменять порядок символов. Например, если у меня есть фрейм данных, который выглядит так:
df <- data.frame(
vars = c('Sepal.Width:Petal.Length' ,
'Sepal.Length:Sepal.Length',
'Sepal.Length:Petal.Length',
'Petal.Length:Sepal.Length',
'Petal.Width:Sepal.Length ',
'Sepal.Length:Petal.Width ',
'Petal.Width:Petal.Length ',
'Sepal.Width:Sepal.Width ',
'Sepal.Width:Sepal.Length '),
value = c(0.18750000,
0.12500000,
0.18750000,
0.09791667,
0.09791667,
0.06666667,
0.02500000,
0.05625000,
0.15625000)
)
Мы видим в столбце var
, что строка 3 — это Sepal.Length:Petal.Length
, а строка 4 — это Petal.Length:Sepal.Length
. Я пытаюсь упорядочить фрейм данных так, чтобы порядок имен был одинаковым. Итак, взяв 3 и 4 строку, я хочу переставить имена, скажем, по алфавиту, чтобы получилось: Petal.Length:Sepal.Length
для обеих строк.
После перестановки всего фрейма данных желаемый результат будет выглядеть примерно так:
var value
1 Petal.Length:PetalWidth. 0.02500000
2 Petal.Length:Sepal.Length 0.09791667
3 Petal.Length:Sepal.length 0.18750000
4 Petal.Length:Sepal.Width 0.18750000
5 Petal.Width:Sepal.Length 0.09791667
6 Petal.Width:Sepal.Length 0.06666667
7 Sepal.Length:Sepal.Length 0.09791667
8 Sepal.Length:Sepal.Width 0.15625000
9 Sepal.Width:Sepal.Width 0.05625000
Вы можете использовать функции tidyverse, чтобы разделить столбец «vars», отсортировать все по алфавиту, а затем снова склеить имена:
library(tidyverse)
result <- df %>%
rowwise() %>%
mutate(
separated = list(sort(strsplit(vars, ':')[[1]])),
trimmed = list(gsub('(^ +| +$)', '', separated)),
reordered = paste(trimmed, collapse = ':')
) %>%
select(vars = reordered, value)
vars value
<chr> <dbl>
1 Petal.Length:Sepal.Width 0.188
2 Sepal.Length:Sepal.Length 0.125
3 Petal.Length:Sepal.Length 0.188
4 Petal.Length:Sepal.Length 0.0979
5 Petal.Width:Sepal.Length 0.0979
6 Petal.Width:Sepal.Length 0.0667
7 Petal.Length:Petal.Width 0.025
8 Sepal.Width:Sepal.Width 0.0562
9 Sepal.Length:Sepal.Width 0.156
С помощью tidyverse
мы можем разделить строку на :
, затем использовать map
, чтобы применить функцию для сортировки, удалить пробелы, а затем снова склеить.
library(tidyverse)
df %>%
mutate(vars = map(
str_split(vars, pattern = ":"),
~ sort(.x) %>% trimws(.) %>% paste0(., collapse = ':')
)) %>%
arrange(vars)
Выход
vars value
1 Petal.Length:Sepal.Width 0.18750000
2 Sepal.Length:Sepal.Length 0.12500000
3 Petal.Length:Sepal.Length 0.18750000
4 Petal.Length:Sepal.Length 0.09791667
5 Petal.Width:Sepal.Length 0.09791667
6 Petal.Width:Sepal.Length 0.06666667
7 Petal.Length:Petal.Width 0.02500000
8 Sepal.Width:Sepal.Width 0.05625000
9 Sepal.Length:Sepal.Width 0.15625000
Или, если вам нужен точный ожидаемый результат, мы могли бы сделать что-то вроде этого:
df %>%
mutate(vars = map(
str_split(vars, pattern = ":"),
~ sort(.x) %>% trimws(.)
)) %>%
mutate(vars = gsub("^c\\(|\\)$", "", vars),
vars = gsub(", +", ",", gsub("\"", "", vars))) %>%
separate(vars, c("vars1", "vars2"), sep = ",") %>%
arrange(vars1, vars2, value) %>%
unite("vars", vars1:vars2, sep = ":")
Выход
vars value
1 Petal.Length:Petal.Width 0.02500000
2 Petal.Length:Sepal.Length 0.09791667
3 Petal.Length:Sepal.Length 0.18750000
4 Petal.Length:Sepal.Width 0.18750000
5 Petal.Width:Sepal.Length 0.06666667
6 Petal.Width:Sepal.Length 0.09791667
7 Sepal.Length:Sepal.Length 0.12500000
8 Sepal.Length:Sepal.Width 0.15625000
9 Sepal.Width:Sepal.Width 0.05625000
Вот еще одно решение, которое дает вам точный «ожидаемый» результат:
library(tidyverse)
df <- data.frame(
vars = c('Sepal.Width:Petal.Length' ,
'Sepal.Length:Sepal.Length',
'Sepal.Length:Petal.Length',
'Petal.Length:Sepal.Length',
'Petal.Width:Sepal.Length ',
'Sepal.Length:Petal.Width ',
'Petal.Width:Petal.Length ',
'Sepal.Width:Sepal.Width ',
'Sepal.Width:Sepal.Length '),
value = c(0.18750000,
0.12500000,
0.18750000,
0.09791667,
0.09791667,
0.06666667,
0.02500000,
0.05625000,
0.15625000)
)
df %>%
separate(vars, into = c("var1", "var2"), sep = ":") %>%
mutate(var2 = str_trim(var2)) %>%
mutate(vars = case_when(var1 < var2 ~ paste(var1, var2, sep = ":"),
var1 > var2 ~ paste(var2, var1, sep = ":"),
TRUE ~ paste(var1, var2, sep = ":"))) %>%
select(vars, value) %>%
arrange(vars, value)
#> vars value
#> 1 Petal.Length:Petal.Width 0.02500000
#> 2 Petal.Length:Sepal.Length 0.09791667
#> 3 Petal.Length:Sepal.Length 0.18750000
#> 4 Petal.Length:Sepal.Width 0.18750000
#> 5 Petal.Width:Sepal.Length 0.06666667
#> 6 Petal.Width:Sepal.Length 0.09791667
#> 7 Sepal.Length:Sepal.Length 0.12500000
#> 8 Sepal.Length:Sepal.Width 0.15625000
#> 9 Sepal.Width:Sepal.Width 0.05625000
Created on 2022-03-21 by the reprex package (v2.0.1)
В основном просто strsplit
, sort
и paste
с использованием базы R (> = 4.1).
df |> transform(vars=sapply(strsplit(vars, ':'), \(x)
paste(trimws(sort(x)), collapse=':'))) |>
{\(.) .[order(.$vars, .$value), ]}()
# vars value
# 7 Petal.Length:Petal.Width 0.02500000
# 4 Petal.Length:Sepal.Length 0.09791667
# 3 Petal.Length:Sepal.Length 0.18750000
# 1 Petal.Length:Sepal.Width 0.18750000
# 6 Petal.Width:Sepal.Length 0.06666667
# 5 Petal.Width:Sepal.Length 0.09791667
# 2 Sepal.Length:Sepal.Length 0.12500000
# 9 Sepal.Length:Sepal.Width 0.15625000
# 8 Sepal.Width:Sepal.Width 0.05625000
Данные:
df <- structure(list(vars = c("Sepal.Width:Petal.Length", "Sepal.Length:Sepal.Length",
"Sepal.Length:Petal.Length", "Petal.Length:Sepal.Length", "Petal.Width:Sepal.Length ",
"Sepal.Length:Petal.Width ", "Petal.Width:Petal.Length ", "Sepal.Width:Sepal.Width ",
"Sepal.Width:Sepal.Length "), value = c(0.1875, 0.125, 0.1875,
0.09791667, 0.09791667, 0.06666667, 0.025, 0.05625, 0.15625)), class = "data.frame", row.names = c(NA,
-9L))