在第一个遇到的数字上通过 dplyr 使用单独的(tidyr)分隔列
Separating column using separate (tidyr) via dplyr on a first encountered digit
我试图将一个相当混乱的列分成两列,包含 period 和 description。我的数据类似于以下摘录:
set.seed(1)
dta <- data.frame(indicator=c("someindicator2001", "someindicator2011",
"some text 20022008", "another indicator 2003"),
values = runif(n = 4))
想要的结果
想要的结果应该是这样的:
indicator period values
1 someindicator 2001 0.2655087
2 someindicator 2011 0.3721239
3 some text 20022008 0.5728534
4 another indicator 2003 0.9082078
特征
- 指标说明在一栏中
- 数值(从第一个数字开始计算,第一个数字在第二列)
代码
require(dplyr); require(tidyr); require(magrittr)
dta %<>%
separate(col = indicator, into = c("indicator", "period"),
sep = "^[^\d]*(2+)", remove = TRUE)
自然这不行:
> head(dta, 2)
indicator period values
1 001 0.2655087
2 011 0.3721239
其他尝试
- 我也尝试过默认的分隔方法
sep = "[^[:alnum:]]"
但它会将列分解为太多列,因为它似乎与所有可用数字匹配。
sep = "2*"
也不起作用,因为有时 2 太多 (例如:20032 006).
我想做的归结为:
- 识别字符串中的第一个数字
- 在那份章程上分居。 事实上,我也很乐意保留那个特定的角色。
我想这也许可以。
library(tidyr)
separate(dta, indicator, c("indicator", "period"), "(?<=[a-z]) ?(?=[0-9])")
# indicator period values
# 1 someindicator 2001 0.2655087
# 2 someindicator 2011 0.3721239
# 3 some text 20022008 0.5728534
# 4 another indicator 2003 0.9082078
以下是regex101.
为大家带来的正则表达式的解释
(?<=[a-z])
是一个积极的回顾 - 它断言 [a-z]
(匹配 a 和 z 之间的范围内存在的单个字符(区分大小写))可以匹配
?
按字面意思匹配前面的space字符,0次到1次之间,尽可能多次,按需回馈
(?=[0-9])
是一个积极的前瞻——它断言 [0-9]
(匹配 0 到 9 范围内的单个字符)可以被匹配
你也可以使用 unglue::unnest()
:
dta <- data.frame(indicator=c("someindicator2001", "someindicator2011",
"some text 20022008", "another indicator 2003"),
values = runif(n = 4))
# remotes::install_github("moodymudskipper/unglue")
library(unglue)
unglue_unnest(dta, indicator, "{indicator}{=\s*}{period=\d*}")
#> values indicator period
#> 1 0.43234262 someindicator 2001
#> 2 0.65890900 someindicator 2011
#> 3 0.93576805 some text 20022008
#> 4 0.01934736 another indicator 2003
由 reprex package (v0.3.0)
于 2019-09-14 创建
我试图将一个相当混乱的列分成两列,包含 period 和 description。我的数据类似于以下摘录:
set.seed(1)
dta <- data.frame(indicator=c("someindicator2001", "someindicator2011",
"some text 20022008", "another indicator 2003"),
values = runif(n = 4))
想要的结果
想要的结果应该是这样的:
indicator period values
1 someindicator 2001 0.2655087
2 someindicator 2011 0.3721239
3 some text 20022008 0.5728534
4 another indicator 2003 0.9082078
特征
- 指标说明在一栏中
- 数值(从第一个数字开始计算,第一个数字在第二列)
代码
require(dplyr); require(tidyr); require(magrittr)
dta %<>%
separate(col = indicator, into = c("indicator", "period"),
sep = "^[^\d]*(2+)", remove = TRUE)
自然这不行:
> head(dta, 2)
indicator period values
1 001 0.2655087
2 011 0.3721239
其他尝试
- 我也尝试过默认的分隔方法
sep = "[^[:alnum:]]"
但它会将列分解为太多列,因为它似乎与所有可用数字匹配。 sep = "2*"
也不起作用,因为有时 2 太多 (例如:20032 006).
我想做的归结为:
- 识别字符串中的第一个数字
- 在那份章程上分居。 事实上,我也很乐意保留那个特定的角色。
我想这也许可以。
library(tidyr)
separate(dta, indicator, c("indicator", "period"), "(?<=[a-z]) ?(?=[0-9])")
# indicator period values
# 1 someindicator 2001 0.2655087
# 2 someindicator 2011 0.3721239
# 3 some text 20022008 0.5728534
# 4 another indicator 2003 0.9082078
以下是regex101.
为大家带来的正则表达式的解释(?<=[a-z])
是一个积极的回顾 - 它断言[a-z]
(匹配 a 和 z 之间的范围内存在的单个字符(区分大小写))可以匹配?
按字面意思匹配前面的space字符,0次到1次之间,尽可能多次,按需回馈(?=[0-9])
是一个积极的前瞻——它断言[0-9]
(匹配 0 到 9 范围内的单个字符)可以被匹配
你也可以使用 unglue::unnest()
:
dta <- data.frame(indicator=c("someindicator2001", "someindicator2011",
"some text 20022008", "another indicator 2003"),
values = runif(n = 4))
# remotes::install_github("moodymudskipper/unglue")
library(unglue)
unglue_unnest(dta, indicator, "{indicator}{=\s*}{period=\d*}")
#> values indicator period
#> 1 0.43234262 someindicator 2001
#> 2 0.65890900 someindicator 2011
#> 3 0.93576805 some text 20022008
#> 4 0.01934736 another indicator 2003
由 reprex package (v0.3.0)
于 2019-09-14 创建