R tidyr::pivot_longer() несколько столбцов

avatar
melmo
8 августа 2021 в 16:07
186
2
1

У меня есть набор данных, содержащий несколько столбцов, как показано ниже:

enter image description here

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

Вот что я пробовал... Но код пытается объединить столбцы Trend и Player Name. Как указать, что это должны быть два отдельных столбца, представленных одной и той же позицией?

  Data_trend <-
    data %>%
    tidyr::pivot_longer(
      cols = !`Trade Value`,
      names_to = c("Position", "Player Name"),
      names_pattern = c("(.*).(.*)"),
    )

Спасибо за помощь!

Вот как воспроизвести данные:

    data <- structure(list(`Trade Value` = c(79, 70.5, 68.5, 67.5, 64, 61, 
57.5, 57, 56.5, 56, 55, 54, 51.5, 51, 49.5, 48.5, 47, 43, 41, 
39.5, 39, 38.5, 38.5, 38, 35, 34.5, 33.5, 32, 30.5, 30), `Running Back.Player Name` = c("Christian McCaffrey", 
"Dalvin Cook", "Alvin Kamara", "", "", "Ezekiel Elliott", "Saquon Barkley", 
"", "Derrick Henry", "", "", "", "Nick Chubb", "Aaron Jones", 
"Jonathan Taylor", "", "", "", "Joe Mixon", "Antonio Gibson", 
"Austin Ekeler", "", "", "", "", "", "", "", "Clyde Edwards-Helaire", 
"J.K. Dobbins"), `Running Back.Trend` = c(0, 0, 0, NA, NA, 0, 
0, NA, 0, NA, NA, NA, 0, 0, 0, NA, NA, NA, 0, 0, 0, NA, NA, NA, 
NA, NA, NA, NA, 0, 0), `Wide Receiver.Player Name` = c("", "", 
"", "", "", "", "", "Stefon Diggs", "Davante Adams", "", "Calvin Ridley", 
"Tyreek Hill", "", "", "", "", "DeAndre Hopkins", "", "", "", 
"A.J. Brown", "D.K. Metcalf", "Justin Jefferson", "", "Terry McLaurin", 
"", "Keenan Allen", "Allen Robinson II", "Mike Evans", ""), `Wide Receiver.Trend` = c(NA, 
NA, NA, NA, NA, NA, NA, 0, 0, NA, 0, 0, NA, NA, NA, NA, 0, NA, 
NA, NA, 0, 0, 0, NA, 0, NA, 0, 0, 0, NA), `Tight End.Player Name` = c("", 
"", "", "", "", "", "", "", "", "", "", "", "Travis Kelce", "", 
"", "", "", "George Kittle", "", "", "", "", "", "Darren Waller", 
"", "", "", "", "", ""), `Tight End.Trend` = c(NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, 0, NA, NA, NA, NA, 0, NA, NA, 
NA, NA, NA, 0, NA, NA, NA, NA, NA, NA), `Quarterback.Player Name` = c("", 
"", "", "Patrick Mahomes II", "Josh Allen", "", "", "", "", "Kyler Murray", 
"", "", "", "", "Lamar Jackson", "Dak Prescott", "", "", "", 
"", "", "Russell Wilson", "", "", "Justin Herbert", "Aaron Rodgers", 
"", "", "", ""), Quarterback.Trend = c(NA, NA, NA, 0, 0, NA, 
NA, NA, NA, 0, NA, NA, NA, NA, 0, 0, NA, NA, NA, NA, NA, 0, NA, 
NA, 0, 0, NA, NA, NA, NA)), row.names = c(NA, 30L), class = "data.frame")
Источник

Ответы (2)

avatar
Chris Ruehlemann
8 августа 2021 в 16:35
4

Вот еще одно решение с более компактным регулярным выражением:

data %>%
  pivot_longer(-1, 
               names_to = c("Position", ".value"), 
               names_pattern = c("([^\\.]+)\\.([^\\.]+)"))

Регулярное выражение состоит из трех элементов:

  • ([^\\.]+): первый шаблон для сопоставления - это класс отрицательных символов, допускающий только символы, которые не периода .
  • \\.: точка, которая здесь служит разделяющим элементом и которую необходимо экранировать как метасимвол
  • ([^\\.]+): второй шаблон для сопоставления - то же объяснение, что и выше

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

намного более скромное решение с names_sep:

data %>%
  pivot_longer(-1, 
               names_to = c("Position", ".value"), 
               names_sep = "\\.")
Anoushiravan R
8 августа 2021 в 16:46
1

Очень милый мистер Рюлеманн. Я серьезно отношусь к регулярным выражениям, поэтому надеюсь учиться у всех таких мастеров, как вы :)

Chris Ruehlemann
8 августа 2021 в 16:47
2

Спасибо за похвалу. Что касается вашего регулярного выражения: я думаю, вы можете сократить его до этого: "(\\D+)\\.(\\D+)"

Chris Ruehlemann
8 августа 2021 в 16:48
2

Это потому, что \\Dсоответствует всему, что не является цифрой; следовательно, он также будет соответствовать \\s, поскольку пробел не является цифрой.

Anoushiravan R
8 августа 2021 в 16:49
0

Да, точно. Я добавлю это в свое решение. Я хотел использовать синтаксис группы без захвата и был рад, что это сработало здесь, возможно, это было слишком много для этого простого случая.

Chris Ruehlemann
8 августа 2021 в 16:54
2

Даже это работает: (.*)\\.(.*), но, как и (\\D+)\\.(\\D+), гораздо менее строгое, чем ([^\\.]+)\\.([^\\.]+).

Anoushiravan R
8 августа 2021 в 17:00
0

Да, точно! Я думаю, что второй и третий более конкретны. У меня есть только один вопрос, и я был бы признателен, если бы вы могли ответить на него. В этой структуре (\\D+(?:\\s\\D+)?), где мы определяем группу без захвата как некое необязательное совпадение внутри группы захвата, нужно ли нам также указывать присутствие с помощью ? в конце? Я пробовал, и без ? это не работает так, как должно. Заранее большое спасибо.

Chris Ruehlemann
8 августа 2021 в 22:40
1

Уважаемый @AnoushiravanR, я вижу, вы действительно заинтересованы в углубленном изучении регулярных выражений. Как я это вижу, но я допускаю, что могу ошибаться, использование (?:\\s\\D+)? не обязательно — избыточно, если хотите — поскольку \\D+ уже охватывает такие строки, как Trend и Player name. Что делает группа без захвата, так это то, что она соответствует параллельному шаблону, который не сохраняется и не выводится (аналогично поиску).

Anoushiravan R
9 августа 2021 в 04:08
0

Большое спасибо, мистер Рюлеманн, вы правы. Я также добавил ваше предложение в верхней части моего решения. Спасибо, что нашли время, чтобы ответить на мой вопрос, надеюсь, я смогу отблагодарить :)

avatar
Anoushiravan R
8 августа 2021 в 16:22
4

Согласно предложению уважаемого г-на Криса Рюлеманна, здесь представлена ​​более компактная версия этого решения:

data %>%
  pivot_longer(!`Trade Value`, names_to = c("Position", ".value"), 
               names_pattern = "(\\D+)\\.(\\D+)")

# A tibble: 120 x 4
   `Trade Value` Position      `Player Name`         Trend
           <dbl> <chr>         <chr>                 <dbl>
 1          79   Running Back  "Christian McCaffrey"     0
 2          79   Wide Receiver ""                       NA
 3          79   Tight End     ""                       NA
 4          79   Quarterback   ""                       NA
 5          70.5 Running Back  "Dalvin Cook"             0
 6          70.5 Wide Receiver ""                       NA
 7          70.5 Tight End     ""                       NA
 8          70.5 Quarterback   ""                       NA
 9          68.5 Running Back  "Alvin Kamara"            0
10          68.5 Wide Receiver ""                       NA
# ... with 110 more rows

Вы можете использовать следующее решение. Основываясь на ваших именах столбцов, я использовал следующую структуру регулярных выражений:

  • \\D+ соответствует любым нецифровым символам, включая пробелы, один или несколько раз поэтому первая группа захвата (\\D+) соответствует имени вроде Running Back.
  • (?:\\s\\D+) это группа без захвата, которую я использовал, которая имеет структуру (?: ...), указывающую необязательный шаблон, здесь это пробел \\s, за которым следует число нецифровых значений \\D+. Я поместил эту группу без захвата во вторую группу захвата, в результате чего получилось (\\D+(?:\\s\\D+)?), так как первый шаблон \\D+ является обязательным, а остальные необязательны и соответствуют, например, Player Name или Trend.

Я определил два набора столбцов в аргументе names_to, поэтому мне пришлось определить две группы захвата в names_pattern, разделенные буквальной точкой . следующим образом:

library(tidyr)

data %>%
  pivot_longer(!`Trade Value`, names_to = c("Position", ".value"), 
               names_pattern = "(\\D+)\\.(\\D+(?:\\s\\D+)?)")

# A tibble: 120 x 4
   `Trade Value` Position      `Player Name`         Trend
           <dbl> <chr>         <chr>                 <dbl>
 1          79   Running Back  "Christian McCaffrey"     0
 2          79   Wide Receiver ""                       NA
 3          79   Tight End     ""                       NA
 4          79   Quarterback   ""                       NA
 5          70.5 Running Back  "Dalvin Cook"             0
 6          70.5 Wide Receiver ""                       NA
 7          70.5 Tight End     ""                       NA
 8          70.5 Quarterback   ""                       NA
 9          68.5 Running Back  "Alvin Kamara"            0
10          68.5 Wide Receiver ""                       NA
# ... with 110 more rows
melmo
8 августа 2021 в 16:29
0

Благодарю вас! Есть ли какая-либо документация, на которую вы могли бы направить меня, чтобы понять регулярное выражение, необходимое для шаблона?

Anoushiravan R
8 августа 2021 в 16:34
1

Я добавлю некоторые детали к этому ответу, чтобы объяснить используемое мной регулярное выражение, но вы можете скачать basic regular expressions in R и stringr шпаргалки по этой ссылке, они очень кратки и эффективны: rstudio.com/resources/cheatsheets

Anoushiravan R
8 августа 2021 в 17:01
0

@melmo Я добавил более компактную версию кода, предложенную уважаемым мистером Рюлеманном, а также немного отредактировал первую, пожалуйста, проверьте их.