将一列拆分为两列并保留分隔符

时间:2015-08-19 05:54:28

标签: regex r split dataframe

我有一个非常大的数据数组:

'data.frame':   40525992 obs. of  14 variables:    
 $ INSTNM     : Factor w/ 7050 levels "A   W Healthcare Educators"     
 $ Total      : Factor w/ 3212 levels "1","10","100",    
 $ Crime_Type : Factor w/ 72 levels "MURD11","NEG_M11",    
 $ Count      : num  0 0 0 0 0 0 0 0 0 0 ...

Crime_Type列包含犯罪类型和年份,因此“MURD11”是2011年的谋杀案。这些是我孩子正在为她的学校项目分析的大学校园犯罪统计数据,我在她被困时正在帮助。我目前只是在创建一个她可以分析的干净数据文件

一旦我使用'gather'将宽文件(列中的所有犯罪类型'9')转换为长文件,文件大小将从300MB变为 8 GB。我正在工作的文件on是8GB。你是那个问题吗?如何将其转换为data.table以加快处理速度?

我想要做的是将split这个'Crime_Type'列分为两列'Crime_Type'和'Year'。数据包含字母数字和数字。还有一些像NEG_M这样的特殊角色是“疏忽的杀人”。

我们稍后会更换全名,但有人可以建议我如何分开

MURD11 - > MURD和11(两列) NEG_M10 - > NEG_M和10(两列)

等...

我尝试过使用,

df <- separate(totallong, Crime_Type, into = c("Crime", "Year"), sep = "[:digit:]", extra = "merge")
df <- separate(totallong, Crime_Type, into = c("Year", "Temp"), sep = "[:alpha:]", extra = "merge")

第一个将犯罪分开,因为它寻找数字。第二个根本不起作用。

我也试过

df$Crime_Type<- apply (strsplit(as.character(df$Crime_Type), split="[:digit:]"))

这根本不起作用。我已经浏览了很多关于堆栈溢出的帖子,这就是我得到这些命令的地方,但我现在真的被困住了,非常感谢你的帮助。

2 个答案:

答案 0 :(得分:2)

由于您已经使用tidyr(由separate证明),请尝试extract函数,在给定正则表达式的情况下,将每个捕获的组放入新列。 'Crime_Type'是所有非数字的东西,'Year'是数字的东西。相应地调整正则表达式。

library(tidyr)
extract(df, 'Crime_Type', into=c('Crime', 'Year'), regex='^([^0-9]+)([0-9]+)$')

答案 1 :(得分:1)

base R中,一个选项是在非数字和数字部分之间创建唯一的分隔符。我们可以将非数字([^0-9]+)和数字([0-9]+)字符包装在括号((..))内,并在替换中使用{{1} }对于第一个捕获组,后跟\\1和第二个组(,)。这可以用作\\2的输入向量,read.table读取为两列。

sep=','

如果需要,我们可以 df1 <- read.table(text=gsub('([^0-9]+)([0-9]+)', '\\1,\\2', totallong$Crime_Type),sep=",", col.names=c('Crime', 'Year')) df1 # Crime Year #1 MURD 11 #2 NEG_M 11 使用原始数据集

cbind

或者在cbind(totallong, df1) 中,我们可以base R使用strsplit指定非数字(split)和数字((?<=[^0-9]))之间的边界。在这里,我们使用(?=[0-9])来匹配边界。输出为lookarounds,我们可以list rbind个元素list并将其转换为do.call(rbind

data.frame

或另一个选项是来自as.data.frame(do.call(rbind, strsplit(as.character(totallong$Crime_Type), split="(?<=[^0-9])(?=[0-9])", perl=TRUE))) # V1 V2 #1 MURD 11 #2 NEG_M 11 的开发版本的tstrsplit,即。 data.table。在这里,我们使用相同的v1.9.5。此外,还可以选择将输出列转换为不同的regex

class

如果我们不需要&#39; Crime_Type&#39;在输出中的列,可以将其分配给library(data.table)#v1.9.5+ setDT(totallong)[, c('Crime', 'Year') := tstrsplit(Crime_Type, "(?<=[^0-9])(?=[0-9])", perl=TRUE, type.convert=TRUE)] # Crime_Type Crime Year #1: MURD11 MURD 11 #2: NEG_M11 NEG_M 11

NULL

注意:安装devel版本的说明是here

或者,在将行折叠为单个字符串(&#39; v2&#39;)之后,来自totallong[, Crime_Type:= NULL] 的{​​{1}}更快的选项。 &#39; v3&#39;中的替代元素可以通过使用stri_extract_all建立索引来提取,以创建新的library(stringi)

seq

基准

data.frame

数据

library(stringi)
v2 <- paste(totallong$Crime_Type, collapse='')
v3 <- stri_extract_all(v2, regex='\\d+|\\D+')[[1]]
ind1 <- seq(1, length(v3), by=2)
ind2 <- seq(2, length(v3), by=2)
d1 <- data.frame(Crime=v3[ind1], Year= v3[ind2])