由于我的csv文件已损坏,因此我使用以下命令将其读入R:
dataDT <- data.table::fread(".../test.csv", sep = NULL)
它为数据集提供了类似的内容:
dataDT <- data.table("ColA,ColB,ColC,ColD" = c("1,10,some text... , some text,,20190801",
"2,22,some text... , some text,,20190801",
"3,30,some text... , some text,,20170601"))
dataDT
> dataDT
ColA,ColB,ColC,ColD
1: 1,10,some text... , some text,,20190801
2: 2,22,some text... , some text,,20190801
3: 3,30,some text... , some text,,20170601
现在,我想要的是将每行中的字符串分成4个新列:
targetDT <- data.table(ColA = c(1,2,3),
ColB = c(10,22,30),
ColC = c("some text... , some text,", "some text... , some text,", "some text... , some text,"),
ColD = c("20190801","20190801",'20170601'))
targetDT
> targetDT
ColA ColB ColC ColD
1: 1 10 some text... , some text, 20190801
2: 2 22 some text... , some text, 20190801
3: 3 30 some text... , some text, 20170601
逻辑将是:
如何实现以上逻辑?
编辑_1:
敏感数据,抱歉,我无法提供确切数据。看起来像:
ID,Code1,Project_Name,Report_Date
1: 123123,1, A & B,20100101
2: 1413,2, C, D and E,20120101
3: 53163,333, F, G,20140303
4: 23453,44,This is a name,20160801
5: 12645,555,5th test, to continue,20190501
因此,第一个逗号之前的所有内容绝对是数字,第一和第二个逗号之间的所有内容也都是数字。上一个逗号之后的所有内容绝对是类似日期的8位数字。中间部分可以包含多个逗号,但不能包含引号(这是fread将逗号视为定界符的原因)。
答案 0 :(得分:6)
这里是一个regex
模式,您可以用它替换前导2和终端数字值附近的逗号,并将它们与周围的文本用空格分隔。使用非空格字符进行分隔可能更安全,因为我的下一步是使用read.*
函数之一或也许再次使用fread
读取“行”。也许使用“ |”作为分隔符?
sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)$",
"\\1 \\2 '\\3' \\4",
dataDT$"ColA,ColB,ColC,ColD" )
[1] "1 10 'some text... , some text,' 20190801" "2 22 'some text... , some text,' 20190801"
[3] "3 30 'some text... , some text,' 20170601"
模式中的括号用于创建“捕获类”,在每种情况下,我都使用“ \ d +”模式“捕获”了任意数量的数字或十进制分隔符。我还将替换模式的单引号引起来的文本(用“。+”捕获)括起来,因此第三列中想要的“内部空间”不会被视为分隔符。 "\\1"
,"\\2"
等是对每个捕获类中捕获的字符的引用,按其在模式中的出现顺序进行排序。参见?regex
。但是,如果使用其他分隔符,则不需要单引号。
这是一个使用“ |”的测试作为sep
。
fread(text =sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)", "\\1|\\2|'\\3'|\\4", dataDT$"ColA,ColB,ColC,ColD" ) ,sep="|")
V1 V2 V3 V4
1: 1 10 'some text... , some text,' 20190801
2: 2 22 'some text... , some text,' 20190801
3: 3 30 'some text... , some text,' 20170601
注意:如果您的数字值包含逗号或前导或尾随货币,则您需要更改示例,因为使用"\\d"
来捕获数字字符组将不再成功。
答案 1 :(得分:1)
使用纵梁的解决方案
library(data.table)
library(stringr)
library(dplyr)
dataDT <- data.table(data = c("1,10,some text... , some text,,20190801",
"2,22,some text... , some text,,20190801",
"3,30,some text... , some text,,20170601"))
dataDT <- dataDT %>%
mutate(
ColA = str_extract(data, "^[^,]*(?=,)"),
ColB = str_extract(data, "(?<=,)[^,]*(?=,)"),
ColD = str_extract(data, "(?<=,)[^,]*$"),
ColC = str_sub(data, nchar(ColA)+nchar(ColB)+3, nchar(data)-nchar(ColD)-1)
) %>%
select(ColA, ColB, ColC, ColD)
dataDT
#> ColA ColB ColC ColD
#> 1 1 10 some text... , some text, 20190801
#> 2 2 22 some text... , some text, 20190801
#> 3 3 30 some text... , some text, 20170601
由reprex package(v0.3.0)于2019-06-27创建
答案 2 :(得分:0)
到目前为止发布的答案建议使用正则表达式的解决方案。
或者,可以考虑列的位置。正如OP指出的那样
- ColA在第一个逗号前有字符串;
- ColB包含介于第一和第二个逗号之间的所有内容;
- ColD在最后一个逗号后有字符串;
- ColC在中间部分有一个字符串(它可能包含其他逗号)。
这个想法是像往常一样使用fread()
和sep = ","
来读取文件,这会导致数据集未对齐。重新整形为长格式后,可以每行标识第一,第二和最后一列以及中间列。这些条目可以指定各自的列名称。在最后一次改版为宽幅格式期间,中间列折叠为ColC
。
library(data.table)
# read file
DT <- fread("
1,10,some text... some text,,20190801
2,22,some text... , some text,,20190801
3,30,some text... ,, some text,,20170601"
, sep = ","
, fill = TRUE
, header = FALSE
, strip.white = FALSE)
请注意,示例数据集已通过插入其他逗号进行修改以具有更实际的测试用例。
读取操作的结果是未对齐且参差不齐的数据集:
DT
V1 V2 V3 V4 V5 V6 V7 1: 1 10 some text... some text 20190801 NA NA 2: 2 22 some text... some text 20190801 NA 3: 3 30 some text... some text NA 20170601
cols <- c("ColA", "ColB", "ColC", "ColD")
# reshape from wide to long format
long <- melt(DT[, rn := .I], "rn", na.rm = TRUE)
# create lookup table to rename column names
lut <- long[, .(variable, col = rep(cols, c(1L, 1L, .N - 3, 1L))), by = rn]
# rename columns by an update join
long[lut, on = .(rn, variable), variable := col][]
# reshape and collapse
dcast(long, rn ~ variable, paste, collapse = ",")
ColA ColB ColC ColD 1: 1 10 some text... some text, 20190801 2: 2 22 some text... , some text, 20190801 3: 3 30 some text... ,, some text 20170601
如果我们看一下中间结果,可以更好地解释这种方法。
在melt()
之后,long
是
rn variable value 1: 1 V1 1 2: 2 V1 2 3: 3 V1 3 4: 1 V2 10 5: 2 V2 22 6: 3 V2 30 7: 1 V3 some text... some text 8: 2 V3 some text... 9: 3 V3 some text... 10: 1 V4 11: 2 V4 some text 12: 3 V4 13: 1 V5 20190801 14: 2 V5 15: 3 V5 some text 16: 2 V6 20190801 17: 3 V7 20170601
由此,创建查找表lut
rn variable col 1: 1 V1 ColA 2: 1 V2 ColB 3: 1 V3 ColC 4: 1 V4 ColC 5: 1 V5 ColD 6: 2 V1 ColA 7: 2 V2 ColB 8: 2 V3 ColC 9: 2 V4 ColC 10: 2 V5 ColC 11: 2 V6 ColD 12: 3 V1 ColA 13: 3 V2 ColB 14: 3 V3 ColC 15: 3 V4 ColC 16: 3 V5 ColC 17: 3 V7 ColD
在加入更新之后并重新调整为宽幅格式之前,long
看起来像
rn variable value 1: 1 ColA 1 2: 2 ColA 2 3: 3 ColA 3 4: 1 ColB 10 5: 2 ColB 22 6: 3 ColB 30 7: 1 ColC some text... some text 8: 2 ColC some text... 9: 3 ColC some text... 10: 1 ColC 11: 2 ColC some text 12: 3 ColC 13: 1 ColD 20190801 14: 2 ColC 15: 3 ColC some text 16: 2 ColD 20190801 17: 3 ColD 20170601
现在,数据项已与它们各自的列名对齐。