DATA
(поскольку я не хочу устанавливать pdftools
, я воссоздаю ваши данные вручную):
data <- c("ABBOTTABAD DISTRICT 1,332,912 216,534", " ABBOTTABAD TEHSIL 981,590 161,445", " ABBOTTABAD CANTONMENT 138,311 21183", " CHARGE NO 01 138,311 21183", " CIRCLE NO 01 12,150 1847", " 023010101 5,131 705", " 023010102 2,654 435", " 023010103 1,004 173", " 023010104 2,216 349", " 023010105 94 14", " 023010106 1,051 171", " CIRCLE NO 02 15,383 2435", " 023010201 1,352 211", " 023010202 1,019 161", " 023010203 4,079 691")
# data is now identical to what you showed as 15 lines of your `data`
ОБРАБОТКА: Разделение строк по пробелам
Обычно в таких случаях это будет сделано:
strsplit(data, "\\s+") # "\\s+" meaning: 1 or more white spaces
Но в этом случае символы могут иметь 1 пробел между словами,
поэтому мы хотим more than 1 white spaces
, то есть "\\s{2,}"
(как минимум два слова) в качестве разделителей столбцов.
Во-вторых, существуют пробелы перед / / после данных, иногда.
Таким образом, мы предварительно очищаем пробелы в начале / конце строки trimws()
Таким образом:
strsplit(trimws(data), "\\s{2,}")
Затем мы можем связать эти значения строка за строкой, используя Reduce()
df <- Reduce(rbind, strsplit(trimws(data), "\\s{2,}"))
rownames(df) <- 1:dim(df)[1] # just give at least numbers as rownames
df <- as.data.frame(df)
выход:
[,1] [,2] [,3]
1 "ABBOTTABAD DISTRICT" "1,332,912" "216,534"
2 "ABBOTTABAD TEHSIL" "981,590" "161,445"
3 "ABBOTTABAD CANTONMENT" "138,311" "21183"
4 "CHARGE NO 01" "138,311" "21183"
5 "CIRCLE NO 01" "12,150" "1847"
6 "023010101" "5,131" "705"
7 "023010102" "2,654" "435"
8 "023010103" "1,004" "173"
9 "023010104" "2,216" "349"
10 "023010105" "94" "14"
11 "023010106" "1,051" "171"
12 "CIRCLE NO 02" "15,383" "2435"
13 "023010201" "1,352" "211"
14 "023010202" "1,019" "161"
15 "023010203" "4,079" "691"
С этого момента вам нужно будет создавать вспомогательные столбцы, в которых есть счетчики, в строке которых появился тип информации ....
Такой подсчет поможет вам разделить фрейм данных на суб-фреймы. split()
будет очень полезно ...
Я написал несколько функций, которые могут быть полезны для классификации «уровня» строки в data
vec путем подсчета, имеет ли оно более k пробелов в начале или нет.
not.more.than.k.leading.whitespaces <- function(s, k) {
!grepl(paste0("^\\s{", k, ",}"), s)
}
leveler <- function(s, k) {
cumsum(not.more.than.k.leading.whitespaces(s, k))
}
Я бы использовал их так:
df$level0 <- leveler(data, 0)
df$level1 <- leveler(data, 5)
df$level2 <- leveler(data, 11)
df$level3 <- leveler(data, 24)
df$level4 <- leveler(data, 37)
# important helper function:
annotate.by.first.row <- function(df, col, col.title) {
# take first row's column content and add it to the df as a column content
info <- df[1, col]
rowsn <- dim(df)[1]
df.new <- df[2:rowsn, ]
df.new[, col.title] <- info
df.new
}
# split data frame to a list of sub data frames
df.l0 <- split(df, df$level0)
# apply our helper function for annotation column generation
# using the information of the first row of the sub data frames
df.a0.l <- lapply(df.l0, annotate.by.first.row, 1, "district")
# cycle through: split, flatten, annotate.by.first.row
# to add next first row information as a column
df.s1.ll <- lapply(df.a0.l, function(df) split(df, df$level1))
df.s1.l <- unlist(df.s1.ll, recursive = FALSE)
df.a1.l <- lapply(df.s1.l, annotate.by.first.row, 1, "thesil")
# repeat the cycles ...
df.s2.ll <- lapply(df.a1.l, function(df) split(df, df$level2))
df.s2.l <- unlist(df.s2.ll, recursive = FALSE)
df.a2.l <- lapply(df.s2.l, annotate.by.first.row, 1, "cantonment")
df.s3.ll <- lapply(df.a2.l, function(df) split(df, df$level3))
df.s3.l <- unlist(df.s3.ll, recursive = FALSE)
df.a3.l <- lapply(df.s3.l, annotate.by.first.row, 1, "charge")
df.s4.ll <- lapply(df.a3.l, function(df) split(df, df$level4))
df.s4.l <- unlist(df.s4.ll, recursive = FALSE)
df.a4.l <- lapply(df.s4.l, annotate.by.first.row, 1, "circle")
# fuse subdata frames by `Reduce(rbind, ...)`
res.df <- Reduce(rbind, df.a4.l)
res.cleaned.df <- res.df[, c("district", "thesil", "cantonment", "charge", "circle", "V1", "V2", "V3")]
Посредством таких последовательных шагов разделения, выравнивания, аннотирования в первом ряду вы можете попасть туда, куда хотите.
> res.cleaned.df
# district thesil cantonment charge
# 6 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 7 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 8 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 9 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 10 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 11 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 13 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 14 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# 15 ABBOTTABAD DISTRICT ABBOTTABAD TEHSIL ABBOTTABAD CANTONMENT CHARGE NO 01
# circle V1 V2 V3
# 6 CIRCLE NO 01 023010101 5,131 705
# 7 CIRCLE NO 01 023010102 2,654 435
# 8 CIRCLE NO 01 023010103 1,004 173
# 9 CIRCLE NO 01 023010104 2,216 349
# 10 CIRCLE NO 01 023010105 94 14
# 11 CIRCLE NO 01 023010106 1,051 171
# 13 CIRCLE NO 02 023010201 1,352 211
# 14 CIRCLE NO 02 023010202 1,019 161
# 15 CIRCLE NO 02 023010203 4,079 691
Чтобы сделать это немного более компактно и регулярно:
# abstract over the split-flatten-annotate cycle/pattern by:
spl.fl.annotate <- function(df.a.l, col, col.name) {
df.sN.ll <- lapply(df.a.l, function(df) split(df, df[, col]))
df.sN.l <- unlist(df.sN.ll, recursive = FALSE)
lapply(df.sN.l, annotate.by.first.row, 1, col.name)
}
# now the cycles can be written as:
df.a0.l <- spl.fl.annotate(list(`0` = df), "level0", "district")
df.a1.l <- spl.fl.annotate(df.a0.l, "level1", "thesil")
df.a2.l <- spl.fl.annotate(df.a1.l, "level2", "cantonment")
df.a3.l <- spl.fl.annotate(df.a2.l, "level3", "charge")
df.a4.l <- spl.fl.annotate(df.a3.l, "level4", "circle")
# fuse subdata frames by `Reduce(rbind, ...)`
res.df <- Reduce(rbind, df.a4.l)
res.cleaned.df <- res.df[, c("district", "thesil", "cantonment", "charge", "circle", "V1", "V2", "V3")]