我有一个如下数据框:
ID
1-1-1, 1-2-1
2-1-1
3-1-1 through 3-5-1
我希望将数据帧转换为
ID
1-1-1
1-2-1
2-1-1
3-1-1
3-2-1
3-3-1
3-4-1
3-5-1
对于第一个数据框中的第一行,我认为融化可以完成这项工作。但对于第三行,我认为我应该以某种方式将“通过”替换为两者之间的ID。我尝试了一些正则表达式,但没有找到一个好方法。
以下问题:
如果有另一列并且我想匹配它们怎么办?
NewColumn ID
A 1-1-1, 1-2-1
B 2-1-1
C 3-1-1 through 3-5-1
到
NewColumn ID
A 1-1-1
A 1-2-1
B 2-1-1
C 3-1-1
C 3-2-1
C 3-3-1
C 3-4-1
C 3-5-1
对于多个新列项,ID中的第一个数字可能相同。
答案 0 :(得分:1)
在使用cSplit
替换splitstackshape
和data.table
后,我们可以使用through
和,
方法使用sub
。
使用正则表达式sub
,我们会匹配是否有零个或多个空格(\\s*
)后跟through
后跟零或更多空格(\\s*
)并替换为,
用于' ID'列。
df1$ID <- sub('\\s*through\\s*', ', ', df1$ID)
现在我们使用cSplit
来分割&#39; ID&#39;使用分隔符作为,
并将方向指定为&#39; long&#39;的列。输出仍然是非数字的。因此,如果我们想制作一个序列,最好将其拆分为数字&#39;。我们使用cSplit
作为分隔符,将默认方向设置为&#39; wide&#39;,然后执行第二次-
。我们得到三列。现在,我们可以使用data.table
方法。我们可以按照ID_1&#39;分组。和&#39; ID_3&#39;列并检查if
组中的元素数量(.N
)是否为>1
。如果有多个元素,我们得到第一个和最后一个元素的序列(这里只有两个元素,所以第一个和第二个,即ID_2列,最后是paste
三个列,并创建一个&# 39; data.frame&#39;
library(splitstackshape)
library(data.table)
ID <- cSplit(cSplit(df1, 'ID', ', ', 'long'), 'ID', '-', type.convert=TRUE)[,
list(ID_2=if(.N>1) ID_2[1]:ID_2[2] else ID_2), by = .(ID_1, ID_3)
][, paste(ID_1, ID_2, ID_3, sep="-")]
d1 <- data.frame(ID, stringsAsFactors=FALSE)
d1
#ID
#1 1-1-1
#2 1-2-1
#3 2-1-1
#4 3-1-1
#5 3-2-1
#6 3-3-1
#7 3-4-1
#8 3-5-1
为了便于理解,可以将代码拆分为块。我们基于&#39;,&#39;创造一个“长”的格式
cLong <- cSplit(df1, 'ID', ', ', 'long')
在下一步中,它将分为&#39; - &#39;我们使用选项type.convert=TRUE
将列转换为各自的类。
cLong1 <- cSplit(cLong, 'ID', '-', type.convert=TRUE)
现在,我们使用data.table
方法,因为cSplit
的输出已经是&#39; data.table&#39;
DT1 <- cLong1[, list(ID_2=if(.N>1)
ID_2[1]:ID_2[2]
else ID_2),
by = .(ID_1, ID_3)]
我们将列粘贴在一起
ID <- do.call(paste, c(DT1[,c(1,3,2), with=FALSE], sep='-'))
并创建&#39; data.frame&#39;
data.frame(ID)
对于后续问题,我们只需要更改cSplit
步骤。我们可以添加&#39; NewColumn&#39;作为分组变量。
df1$ID <- sub('\\s*through\\s*', ', ', df1$ID)
cSplit(cSplit(df1, 'ID', ', ', 'long'), 'ID', '-',
type.convert=TRUE)[, list(ID_2=if(.N>1) ID_2[1]:ID_2[2] else ID_2),
by = .(NewColumn, ID_1, ID_3)
][,list(ID=paste(ID_1, ID_2, ID_3, sep="-")) ,.(NewColumn)]
# NewColumn ID
#1: A 1-1-1
#2: A 1-2-1
#3: B 2-1-1
#4: C 3-1-1
#5: C 3-2-1
#6: C 3-3-1
#7: C 3-4-1
#8: C 3-5-1
df1 <- structure(list(ID = c("1-1-1, 1-2-1", "2-1-1",
"3-1-1 through 3-5-1")), .Names = "ID", class = "data.frame",
row.names = c(NA, -3L))
#newdata
df1 <- structure(list(NewColumn = c("A", "B", "C"),
ID = c("1-1-1, 1-2-1",
"2-1-1", "3-1-1 through 3-5-1")), .Names = c("NewColumn", "ID"
), class = "data.frame", row.names = c(NA, -3L))