Переименование столбцов в R 4.3 с использованием собственного канала

У меня есть последовательность операций, для выполнения которых я использую канал R 4.3:

df <- alfred::get_alfred_series(CHAUVET_PIGER_PROB)
unrevised_df <- df |>
                    within(Delta <- realtime_period - date) |>
                    na.omit() |>
                    subset(Delta == ave(Delta, date, FUN = min)) |>
                    subset(Delta <60) |>
                    within(date <- zoo::as.yearmon(format(date, format = '%Y-%m-%d'))) |>
                    subset(select = -c(Delta, realtime_period))


> head(unrevised_df)
           date UNRATE
146  1960-02-01    4.8
1065 1960-03-01    5.4
1984 1960-04-01    5.0
2903 1960-05-01    4.9
3822 1960-06-01    5.5
4741 1960-07-01    5.4

Я хотел бы добавить еще одну строку в свою последовательность, чтобы изменить имя первого столбца с date на Date без необходимости вызывать dplyr. Я знаю, что могу просто добавить отдельную строку следующего содержания: colnames(unrevised_df[1]) <- "Date"

но я хотел бы сделать это строкой в ​​трубе. Как я могу это сделать?

Ваша помощь очень ценится.

Искренне

Томас Филипс

Глупый вопрос, но зачем его переименовывать, если можно сразу назвать правильно within(Date <- zoo::as.yearmon(format(date, format = '%Y-%m-%d')))?

thothal 01.08.2024 09:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Хотя мне кажется странным писать Date = date, date = NULL, использовать transform() легко и просто:

1)

> df |> 
+   transform(Date = date, date = NULL)
     UNRATE       Date
146     4.8 1960-02-01
1065    5.4 1960-03-01
1984    5.0 1960-04-01
2903    4.9 1960-05-01
3822    5.5 1960-06-01
4741    5.4 1960-07-01

2) Жестко запрограммировано с использованием colnames()

df |> 
  `colnames<-`(c("Date", "Unrate"))

3) Небольшая обертка

rename = \(df, pos, nm) {
  stopifnot(is.data.frame(df))
  names(df)[pos] = nm
  df
}

df |>
  rename(df=_, 1L, "Date")

4) Для более чем одного имени

rename2 = \(df, new, old) {
  stopifnot(is.data.frame(df), length(old) == length(new), is.character(new))
  # this check needs to be revised:
  if (! inherits(old, c("numeric", "character", "integer"))) 
    stop("Specify 'old' either as character or integer/numeric.") 
  if (is.character(old)) 
    if (all(sapply(old, \(x) x %in% names(df))==FALSE)) 
      stop("Names in 'old' do not match with names of df.") else 
        names(df)[match(old, names(df))] = new 
      else names(df)[old] = new 
  df
}

mtcars |>
  rename2(c("lala", "blabla"), c("am", "disp"))

mtcars |>
  rename2(c("lala", "blabla"), 7:8)

Данные

df = read.table(text  = "          date UNRATE
146  1960-02-01    4.8
1065 1960-03-01    5.4
1984 1960-04-01    5.0
2903 1960-05-01    4.9
3822 1960-06-01    5.5
4741 1960-07-01    5.4", header = TRUE)
df |> colnames<-(c("Date", "Unrate")) удивительно просто, но я, похоже, не могу изменить только первое имя (второе будет варьироваться в зависимости от того, что загружается. Я попробовал df |> colnames[1]<-` ("Date" )` но ничего не получилось. Я хотел бы оставить Date в качестве первого столбца, если смогу.
Thomas Philips 01.08.2024 08:31

Используйте обертку.

Friede 01.08.2024 08:33

ХОРОШО. Я надеялся, что в R будет встроенная функция, похожая на rename.

Thomas Philips 01.08.2024 08:35

@ThomasPhilips, у tidyverse, безусловно, есть недостатки - как вы упомянули в другом вопросе, API часто меняется. Одна из причин этого заключается в том, что много внимания уделяется тому, как создавать согласованные и удобные для пользователя функции. Если вы хотите обменять tidyverse на базу R, чтобы добиться стабильности, вам придется пожертвовать некоторым удобством.

SamR 01.08.2024 09:19

Также @Friede, когда вы говорите, что ваш первый подход неэффективен, вы имеете в виду набор текста? Он не копирует данные.

SamR 01.08.2024 09:41

@SamR, да, мне кажется неприятно печатать Date = date, date = NULL. Спасибо, я внес ясность.

Friede 01.08.2024 10:28

@SamR Хорошая мысль, и я готов на эту сделку. Я не особенно хороший программист (считайте меня одним из тех, кто поместил Overflow в StackOverflow), поэтому, как только я что-то разберу, я бы хотел, чтобы так и осталось. Я попробовал tidyverse несколько лет назад и был удивлен тем, как часто все меняется. Затем друг рассказал мне, что у него был такой же опыт, и посоветовал мне, насколько это возможно, придерживаться базы R и при необходимости использовать тщательно подобранные пакеты.

Thomas Philips 03.08.2024 10:51
Ответ принят как подходящий

Вот еще несколько подходов. Первый использует анонимную функцию, а остальные используют трюк с помещением входных данных в список.

# 1
unrevised_df |>
  (\(x) { names(x)[1] <- "Date"; x })()

# 2
unrevised_df |>
  list(x = _) |>
  with( { names(x)[1] <- "Date"; x } )

# 3
unrevised_df |>
  list(x = _) |>
  with( setNames(x, replace(names(x), 1, "Date")) )

# 4
unrevised_df |>
  list(x = _) |>
  with(cbind(Date = x[[1]], x[-1]))

Если вы хотите использовать magrittr (который очень стабилен и не требует использования dplyr, tidyr или любого другого пакета tidyverse), мы можем сделать это:

# 5
library(magrittr)
unrevised_df %>%
  { names(.)[1] <- "Date"; . } 

Канал Bizarro на самом деле не канал, а просто базовый синтаксис R, который выглядит примерно так:

# 6
unrevised_df ->.;
  { names(.)[1] <- "Date"; . } 

Другая возможность — определить свою собственную трубку. Этот канал не выполняет автоматическую замену, а вместо этого требует использования точки (.) с правой стороны. Для его определения требуется всего лишь одна дополнительная строка кода, сохраняющая независимость кода от каких-либо пакетов.

"%.>%" <- function(left, right) eval(substitute(right), list(. = left))

unrevised_df %.>%
  { names(.)[1] <- "Date"; . } 

Примечание

Ввод в воспроизводимой форме

unrevised_df <- data.frame(
  date = c("1960-02-01", "1960-03-01", "1960-04-01", "1960-05-01", "1960-06-01", "1960-07-01"),
  UNRATE = c(4.8, 5.4, 5, 4.9, 5.5, 5.4),
  row.names = c("146", "1065", "1984", "2903", "3822", "4741")
)

Я бы использовал unrevised_df |> ``colnames<-``(c("Date", new_name)), где newname передается в качестве параметра в функцию, но я также попробую №1 и №5. (Только один обратный апостроф вокруг имен столбцов). Спасибо, как всегда.

Thomas Philips 02.08.2024 05:34

@Томас, я думаю, ты имел в виду unrevised_df |> `colnames<-`(c("Date", "UNRATE")), но я подумал, что идея вопроса состоит в том, чтобы избежать необходимости заменять все имена. (В комментариях к SO вы можете использовать обратную косую черту для защиты обратных кавычек.)

G. Grothendieck 02.08.2024 12:48

Добавлен альтернативный вариант (7).

G. Grothendieck 03.08.2024 15:47

Другие вопросы по теме