Превращение символьных столбцов, содержащих числа, в числовые в R

Я работаю с набором данных, в котором некоторые данные располагаются способами, которые не очень полезны для дальнейшей работы. Например:

ID Group timestamp location
1    2     12 secs c(50,120)
2    1     3 secs  c(20,45)
3    1     7 secs  c(12,30)
4    2     18 secs c(45,100)
5    3     4 secs  c(0,80)

Я хочу разделить столбец местоположения на два числовых столбца и сделать столбец временной метки числовым, чтобы работать с ними как таковыми.

Пытался удалить символы и использовать as.numeric, но при запуске любого mutate орка со столбцами получаю ошибку non-numeric argument to binary operator.

data= data %>%
  mutate(timestamp = gsub("\\secs", "", timestamp)) %>%
  mutate(location = gsub("\\c()", "", location)) %>%
  separate(location, c("location.x", "location.y"), sep = ",") %>%
  drop_na(timestamp,
          location.y)

as.numeric(data$timestamp)
as.numeric(data&location.y)

data = data %>%
  group_by(Group) %>%
  mutate(av_location.y = mean(location.y),
         av_time = max(timestamp) - min(timestamp))

Если кто-нибудь знает, как я могу обойти эту проблему с вектором символов, я буду признателен.

Я сомневаюсь, что это векторы символов. Не могли бы вы отредактировать свой вопрос, включив в него dput(data)? Спасибо!

jpsmith 05.09.2024 16:28

Вам не нужны обратные косые черты ни в "\\secs", ни в "\\c()".

Rui Barradas 05.09.2024 16:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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
2
63
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Предполагая, что вы действительно имеете дело с символьными столбцами:

library(dplyr, warn.conflicts = FALSE)
data <- tribble(
~ID, ~Group, ~timestamp, ~location,
 1,   2,     "12 secs", "c(50,120)",
 2,   1,     "3 secs" , "c(20,45)",
 3,   1,     "7 secs" , "c(12,30)",
 4,   2,     "18 secs", "c(45,100)",
 5,   3,     "4 secs" , "c(0,80)") 


data |> 
  mutate(timestamp = readr::parse_number(timestamp),
         location = purrr::map(location, \(loc) textConnection(loc) |> dget())) |> 
  tidyr::unnest_wider(location, names_sep = ".")
#> # A tibble: 5 × 5
#>      ID Group timestamp location.1 location.2
#>   <dbl> <dbl>     <dbl>      <dbl>      <dbl>
#> 1     1     2        12         50        120
#> 2     2     1         3         20         45
#> 3     3     1         7         12         30
#> 4     4     2        18         45        100
#> 5     5     3         4          0         80

Выражения типа as.numeric(data$timestamp) сами по себе не сохраняют никаких изменений, вам нужно будет присвоить этот результат, т.е.

data$timestamp <- as.numeric(data$timestamp)
Ответ принят как подходящий

Мы предполагаем, что данные воспроизводимо показаны в примечании в конце. Это либо выглядит как data, где столбец location представляет собой символ, либо как data2, где столбец location представляет собой список числовых векторов. Код обрабатывает оба варианта, но если это вектор символов, то строку {...} можно при желании опустить, ничего не меняя.

Извлеките временную метку, используя separate. Это также создаст ненужный столбец, который мы устраним, используя показанную NA. convert=TRUE приводит к преобразованию номеров символов в числовые.

Следующая строка проверяет, является ли location столбцом списка, и если да, то преобразует его в символьный столбец. Эту строку можно было бы опустить, если бы мы знали, что location — это символ.

Наконец, снова используйте separate на location.

library(dplyr)
library(tidyr)

data %>%
  separate(timestamp, c("timestamp", NA), convert = TRUE) %>%
  { if (is.list(.$location)) mutate(., location = paste(location)) else . } %>%
  separate(location, c(NA,"location1", "location2", NA), convert = TRUE)

предоставление

  ID Group timestamp location1 location2
1  1     2        12        50       120
2  2     1         3        20        45
3  3     1         7        12        30
4  4     2        18        45       100
5  5     3         4         0        80

Примечание

data <- data.frame(
  ID = 1:5,
  Group = c(2L, 1L, 1L, 2L, 3L),
  timestamp = c("12 secs", "3 secs", "7 secs", "18 secs", "4 secs"),
  location = c("c(50,120)", "c(20,45)", "c(12,30)", "c(45,100)", "c(0,80)")


data2 <- data %>%
  mutate(location = lapply(location, \(x) eval(parse(text = x))))

Спасибо. Решение для отметки времени работает хорошо. Оказывается, столбец местоположения представляет собой тип списка, а не символ, который мне удалось разделить с помощью unrest_wider вот так: data = data %>% separate(timestamp, c("timestamp", NA), convert = TRUE) %>% unnest_wider(location, names_sep = ",")

Dan Pritchard 05.09.2024 21:56

На всякий случай, если кому-то интересно, вот как я бы это сделал, используя только базовые функции R. Было бы немного странно использовать базу R для работы с тибблом, но это работает, и, возможно, это поможет кому-то еще с аналогичным вопросом.

Я использую gsub() для удаления нечисловых символов, strsplit() для отделения двух местоположений друг от друга и lapply() для получения только первого или только второго элемента каждого элемента списка. Смотрите комментарии в коде!

Спасибо пользователю margusl (из другого ответа) за код для создания данных.

library(dplyr)
## stack overflow user margusl's code to create your data: 
data <- tribble(
  ~ID, ~Group, ~timestamp, ~location,
  1,   2,     "12 secs", "c(50,120)",
  2,   1,     "3 secs" , "c(20,45)",
  3,   1,     "7 secs" , "c(12,30)",
  4,   2,     "18 secs", "c(45,100)",
  5,   3,     "4 secs" , "c(0,80)")

## Make a new column that removes non-numeric characters from the
## timestamps and converts the type to numeric
data$time <- as.numeric(gsub("\\D", "", data$timestamp))

## Split the strings containing the two locations by the comma so we
## have a list of vectors each of length 2 where the first element has
## the first location and the second has the second
split_by_comma <- strsplit(data$location, ',')

## Then get the first element from each list element
data$loc1 <- lapply(split_by_comma, '[', 1)
## And remove all non-numeric characters and convert to numeric type
data$loc1 <- as.numeric(gsub("\\D", "", data$loc1))

## Repeat for the second element of each list element 
data$loc2 <- lapply(split_by_comma, '[', 2)
data$loc2 <- as.numeric(gsub("\\D", "", data$loc2))

Неоптимизированный базовый подход R,

lapply(df0[sapply(df0, is.character)], \(a) { 
  lapply(regmatches(a, gregexpr("[[:digit:]]+", a)) , strtoi) |> 
    list2DF() |> t() }) |> do.call(what = "cbind") |> 
  `colnames<-`(c("timestamp", "location.1" ,"location.2")) 

который не включает проверки (длины), дает

 timestamp location.1 location.2
        12         50        120
         3         20         45
         7         12         30
        18         45        100
         4          0         80

Другим вариантом может быть

cbind(strtoi(sub("\\D+", "", df0$timestamp)), 
      t(vapply(df0$location, \(i) eval(str2expression(i)), numeric(2L), USE.NAMES=FALSE))) |>
  `colnames<-`(c("timestamp", "location.1" ,"location.2")) 

(где , USE.NAMES=FALSE))) |> `colnames<-`(c("timestamp", "location.1" ,"location.2")) — косметика и может быть заменена одним закрывающимся ).)

Это очень редко. Я подозреваю, что мы имеем дело с xy-проблемой . Откуда берется location = c("c(50,120)", "c(20,45)", ...)?

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