【问题标题】:Splitting unspecific length string into columns将非特定长度字符串拆分为列
【发布时间】:2018-07-31 20:26:10
【问题描述】:

我有一列字符串,我正在尝试将它们拆分为列。我在网上阅读了几篇文章(在底部),但我认为这是不同的。

stringColumn <- c(
  "50m 26.50 26.50 100m 53.82 27.32",                                     
  NA,                                                                      
  "50m 25.83 25.83 100m 52.99 27.16",                                      
  "25m 12.46 12.46 50m 26.26 13.80 75m 40.02 13.76 100m 53.48 13.46",      
  NA,                                                                      
  "25m 11.72 11.72 50m 25.33 13.61 75m 39.15 13.82 100m 52.55 13.40",      
  "50m 27.20 27.20 100m 56.38 29.18 150m 1:26.39 30.01 200m 1:56.16 29.77")

这会持续一段时间(970K 行),并且字符串遵循相同的格式,要么是 NA,要么是 (measurement totaltime timeatcurrentpoint, repeating)。因为不相等,所以不能使用正则表达式或str_split。我的目标是获得一个数据框,其中包含测量的列名(25m、50m、100m 等)以及该点的总时间。

期望的输出:

25m     50m     75m     100m    150m  200m    
NA      26.5    NA      53.82   NA    NA       
NA      NA      NA      NA      NA    NA       
12.46   26.26   40.02   53.48   NA    NA       
NA      NA      NA      NA      NA    NA       
11.72   25.33   39.15   52.55   NA    NA       
NA      27.2    NA      56.38   NA    1:56.16 

【问题讨论】:

  • 那么这个特定样本输入的期望输出是什么?
  • 并非如此。我希望列的名称为 25m、50m 等,这始终是字符串中的 1+3x 位置,列中的时间是字符串中的 2+3x 位置。你的答案没有给出。

标签: r string dataframe


【解决方案1】:

这是使用tidyverse 工具的一种方式。我们可以:

  1. 使用str_split(?=\\d+?m) 前瞻仅在距离之间的标记处拆分每个字符串(即空格后跟一些数字和m);
  2. 放入tibble,添加rowid 列,以便我们知道哪些测量值来自哪些字符串;
  3. unnest 所以每次测量都在自己的行上;
  4. separate 所以measurement、totaltime和current time都有自己的列,丢弃当前时间
  5. spread 对列标题进行测量。

请注意,这与您的示例输出不太匹配,忽略列顺序,但我认为它正确对应于输入。

library(tidyverse)

stringColumn = c(
  "50m 26.50 26.50 100m 53.82 27.32",
  NA,
  "50m 25.83 25.83 100m 52.99 27.16",
  "25m 12.46 12.46 50m 26.26 13.80 75m 40.02 13.76 100m 53.48 13.46",
  NA,
  "25m 11.72 11.72 50m 25.33 13.61 75m 39.15 13.82 100m 52.55 13.40",
  "50m 27.20 27.20 100m 56.38 29.18 150m 1:26.39 30.01 200m 1:56.16 29.77"
)

stringColumn %>%
  str_split(" (?=\\d+?m)") %>%
  tibble(strings = .) %>%
  rowid_to_column(var = "stringid") %>%
  unnest(strings) %>%
  separate(strings, c("measurement", "totaltime", "timeatcurrentpoint"), sep = " ") %>%
  select(-timeatcurrentpoint) %>%
  spread(measurement, totaltime)
#> # A tibble: 7 x 8
#>   stringid `100m` `150m`  `200m`  `25m` `50m` `75m` `<NA>`
#>      <int> <chr>  <chr>   <chr>   <chr> <chr> <chr> <chr> 
#> 1        1 53.82  <NA>    <NA>    <NA>  26.50 <NA>  <NA>  
#> 2        2 <NA>   <NA>    <NA>    <NA>  <NA>  <NA>  <NA>  
#> 3        3 52.99  <NA>    <NA>    <NA>  25.83 <NA>  <NA>  
#> 4        4 53.48  <NA>    <NA>    12.46 26.26 40.02 <NA>  
#> 5        5 <NA>   <NA>    <NA>    <NA>  <NA>  <NA>  <NA>  
#> 6        6 52.55  <NA>    <NA>    11.72 25.33 39.15 <NA>  
#> 7        7 56.38  1:26.39 1:56.16 <NA>  27.20 <NA>  <NA>

【讨论】:

  • 谢谢!无论如何要按顺序获得25m,50m,75m等吗?我可以去掉'm'的原始字符串,但我似乎无法将它作为一个数字。因为我有它直到 10,000m(乘 25m),所以这不是一个简单的重新排序。
  • 你知道全套价值观吗?不幸的是,您不能将整数设置为列名,因此您需要去除 m,转换为整数,排序,然后转换回字符并使用它对数据框进行排序
【解决方案2】:

我们可以将您的数据更改为表达式并对其进行评估:

stringColumn2 <-  gsub("\\s*(\\d+m)\\s*","'),`\\1`=c('",stringColumn[!is.na(stringColumn)])
stringColumn3 <-  paste0(gsub("^'),","list(",stringColumn2),"'))")
stringColumn4 <-  gsub("\\s+","','",stringColumn3)
stringColumn5 <- paste0("list(",paste(stringColumn4,collapse=","),")")

library(dplyr)
bind_rows(eval(parse(text=stringColumn5)),.id = "id")
# # A tibble: 10 x 7
#    id    `50m` `100m` `25m` `75m` `150m`  `200m` 
#    <chr> <chr> <chr>  <chr> <chr> <chr>   <chr>  
#  1 1     26.50 53.82  <NA>  <NA>  <NA>    <NA>   
#  2 1     26.50 27.32  <NA>  <NA>  <NA>    <NA>   
#  3 2     25.83 52.99  <NA>  <NA>  <NA>    <NA>   
#  4 2     25.83 27.16  <NA>  <NA>  <NA>    <NA>   
#  5 3     26.26 53.48  12.46 40.02 <NA>    <NA>   
#  6 3     13.80 13.46  12.46 13.76 <NA>    <NA>   
#  7 4     25.33 52.55  11.72 39.15 <NA>    <NA>   
#  8 4     13.61 13.40  11.72 13.82 <NA>    <NA>   
#  9 5     27.20 56.38  <NA>  <NA>  1:26.39 1:56.16
# 10 5     27.20 29.18  <NA>  <NA>  30.01   29.77  

中间步骤:

stringColumn2[1]
# [1] "'),`50m`=c('26.50 26.50'),`100m`=c('53.82 27.32"
stringColumn3[1]
# [1] "list(`50m`=c('26.50 26.50'),`100m`=c('53.82 27.32'))"
stringColumn4[1]
# [1] "list(`50m`=c('26.50','26.50'),`100m`=c('53.82','27.32'))"

【讨论】:

  • 哇!谢谢你。如果我只想要最后一次(所以第一次是 53.82 而不是 100m 的 27.32)我会怎么做?
  • 这是你想要的吗?您在编辑后的答案中的输出似乎有所不同。我可以轻松地调整我的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-20
  • 1970-01-01
  • 1970-01-01
  • 2015-10-05
相关资源
最近更新 更多