Переставить один столбец в фрейм данных с двумя столбцами - PullRequest
2 голосов
/ 02 мая 2020

У меня большой файл, который организован очень неудобно, все значения в одном столбце с семью значениями на ячейку, кроме двух последних строк, например:

df <- c('(98440=9) (98450=9) (98500=9) (98520=9) (98530=9) (98540=9) (98550=9)',
'(98555=9) (98560=9) (98570=9) (98590=9) (98600=9) (98620=9) (98630=9)',
'(98690=9) (98920=3) (98930=5) (98940=5) (98950=9) (98990=11) (99900=-1)',
'(99910=11) (99920=-1) (99930=11)',
'(-1=-1) (-2=-1) (99999=-1)')

Я хочу только чтобы сохранить числовые значения и в то же время разделить первое и второе числовые значения на два столбца, где '=' - это разделитель, например:

      x     y
  <dbl> <dbl>
1 98440     9
2 98450     9
3 98500     9

Мне удалось два добиться этого, используя отдельный в dplyr, подстрока и некоторый другой код. Тем не менее, я потерял много данных. Любые идеи о том, как это исправить и сохранить все данные? Я понимаю, что это часто задаваемый вопрос, но этот набор данных немного более грязный, чем все, что я видел.

Ответы [ 3 ]

3 голосов
/ 02 мая 2020

Два решения:

Вот двухэтапное решение с использованием str_extract из пакета stringr.

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

df1 <- unlist(strsplit(df, " "))

Второй шаг - разделить значения на = и назначить половинки значения двум столбцам нового фрейма данных:

df2 <- data.frame(
  col1 = str_extract(df1, "(-)?\\d+(?==)"),
  col2 = str_extract(df1, "(?<==)(-)?\\d+")
)

В качестве альтернативы приведем одношаговое решение с использованием str_extract_all:

df1 <- data.frame(
  col1 = unlist(str_extract_all(df, "(-)?\\d+(?==)")),
  col2 = unlist(str_extract_all(df, "(?<==)(-)?\\d+"))
)

РЕДАКТИРОВАТЬ:

Если данные являются частью кадра данных с данными для разделения, называемыми Var1, код будет следующим:

df1 <- data.frame(
  col1 = unlist(str_extract_all(df$Var1, "(-)?\\d+(?==)")),
  col2 = unlist(str_extract_all(df$Var1, "(?<==)(-)?\\d+"))
)

Результат:

df2
    col1 col2
1  98440    9
2  98450    9
3  98500    9
4  98520    9
5  98530    9
6  98540    9
7  98550    9
8  98555    9
9  98560    9
10 98570    9
11 98590    9
12 98600    9
13 98620    9
14 98630    9
15 98690    9
16 98920    3
17 98930    5
18 98940    5
19 98950    9
20 98990   11
21 99900   -1
22 99910   11
23 99920   -1
24 99930   11
25    -1   -1
26    -2   -1
27 99999   -1
1 голос
/ 03 мая 2020

Неудобно упорядоченные неопрятные данные - это то, для чего был создан тидиверс!

library(tidyverse)

c('(98440=9) (98450=9) (98500=9) (98520=9) (98530=9) (98540=9) (98550=9)',
  '(98555=9) (98560=9) (98570=9) (98590=9) (98600=9) (98620=9) (98630=9)',
  '(98690=9) (98920=3) (98930=5) (98940=5) (98950=9) (98990=11) (99900=-1)',
  '(99910=11) (99920=-1) (99930=11)',
  '(-1=-1) (-2=-1) (99999=-1)') %>%

  purrr::map(~ str_split(.," ")) %>% # split each string into its individual components

  unlist() %>%

  tibble::enframe(NULL,"Numbers") %>%

  dplyr::mutate(Numbers = str_replace_all(Numbers,"[()]","")) %>% # remove the brackets as they are unnecessary

  tidyr::separate(Numbers,c("Number 1","Number 2"),sep = "=") # separate using "=" as the separator

Тот же код работает, если вы передаете в него кадр данных на первом шаге вместо символьного вектора.

1 голос
/ 02 мая 2020

Классически, с использованием gsub и strsplit.

df <- 
  data.frame(matrix(as.double(unlist(strsplit(gsub("[\\(\\)]", "", v), "=|\\s"))),,2, b=T))

#       V1 V2
# 1  98440  9
# 2  98450  9
# 3  98500  9
# 4  98520  9
# 5  98530  9
# 6  98540  9
# 7  98550  9
# 8  98555  9
# 9  98560  9
# 10 98570  9
# 11 98590  9
# 12 98600  9
# 13 98620  9
# 14 98630  9
# 15 98690  9
# 16 98920  3
# 17 98930  5
# 18 98940  5
# 19 98950  9
# 20 98990 11
# 21 99900 -1
# 22 99910 11
# 23 99920 -1
# 24 99930 11
# 25    -1 -1
# 26    -2 -1
# 27 99999 -1

Данные

v <- c("(98440=9) (98450=9) (98500=9) (98520=9) (98530=9) (98540=9) (98550=9)", 
"(98555=9) (98560=9) (98570=9) (98590=9) (98600=9) (98620=9) (98630=9)", 
"(98690=9) (98920=3) (98930=5) (98940=5) (98950=9) (98990=11) (99900=-1)", 
"(99910=11) (99920=-1) (99930=11)", "(-1=-1) (-2=-1) (99999=-1)"
)
...