Сделать векторы одинаковой длины в R - PullRequest
1 голос
/ 09 марта 2020

Эта задача не так проста, как предполагает заголовок. Для меня лучше просто использовать неудачный пример, чтобы объяснить, чего я хочу. У меня есть два вектора x и y ...

x <- c("Description 1 2 3 4","5 6 7 8 9 10 11 12","13 14 15 16 17","18 19 20 21 22","23 24 25","26 27 28","","29","30 31","Tot") 
y <- c("Minutes","","","35","60 60 30","60 60","","15","60 60","440")
rbind(x,y)

x "Description 1 2 3 4"     "5 6 7 8 9 10 11 12" "13 14 15 16 17" "18 19 20 21 22" "23 24 25" "26 27 28" ""   "29" "30 31" "Tot"
y "Minutes"                 ""                   ""               "35"             "60 60 30" "60 60"    ""   "15" "60 60" "440"

Мне нужны минуты для выравнивания для определенных c дней из таблицы PDF. Это помогает увидеть, что я хочу, если вы посмотрите на x и y вместе взятые (см. Выше). Для каждой «колонки», если минуты имеют более одного дня над ними, мне нужно перенести минуты на последний день. Например, в дни 18-22 мы видим, что на один из этих дней было 35 минут ... Мне нужно сместить эти 35 минут, чтобы они соответствовали 22-му дню месяца. Для каждого дня, у которого нет ни одной минуты, мне нужно дать этому значению NA. Результат должен выглядеть следующим образом ...

result <- data.frame(rbind(seq(1:31),c(rep(NA,21),35,60,60,30,NA,60,60,15,60,60)))
result

X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 X31
1  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31
2 NA NA NA NA NA NA NA NA NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  35  60  60  30  NA  60  60  15  60  60

Любая помощь приветствуется!

Обновление:

Я смог решить проблема со следующим кодом ...

z <- rbind(x,y)
z <- z[,-ncol(z)]
result <- lapply(1:ncol(z),function(x){
    print(x)
    col <- z[,x]
    row1 <- do.call("c",str_extract_all(col[1],"\\(?[0-9,.]+\\)?"))
    row2 <- do.call("c",str_extract_all(col[2],"\\(?[0-9,.]+\\)?"))
    if(length(row2) == 0) {
        w <- rbind(row1,rep(NA,length(row1)))
    } else {
        w <- rbind(row1,c(rep(NA,length(row1)-length(row2)),row2))
    }
    w
})
do.call("cbind",result)

Было бы интересно увидеть решения других людей.

1 Ответ

0 голосов
/ 10 марта 2020

Вот другой подход - посмотрите, что вы думаете.

# First four lines are from your original post
x <- c("Description 1 2 3 4","5 6 7 8 9 10 11 12","13 14 15 16 17","18 19 20 21 22","23 24 25","26 27 28","","29","30 31","Tot")
y <- c("Minutes","","","35","60 60 30","60 60","","15","60 60","440")
z <- rbind(x,y)
z <- z[,-ncol(z)]

# Function to extract numbers
match_fxn <- function(x) { 
  matches <- regmatches(x, gregexpr("[[:digit:]]+", x))
  as.numeric(unlist(matches))
}

# Create nested matrix of extracted numbers, 
mat <- apply(z, 1:2, match_fxn)

# Force lengths to be same between rows 1 and 2 (adds NAs)
min_list <- mapply(`length<-`, x = mat[2,], Var = lengths(mat[1,]))

# Sort so that NAs are in the beginning
min_sort <- lapply(min_list, function(x) c(x[is.na(x)], x[!is.na(x)]))

# Add rows 1 and 2 to show final result
rbind(unlist(mat[1,]), unlist(min_sort))

Вывод

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30] [,31]
[1,]    1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25    26    27    28    29    30    31
[2,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    35    60    60    30    NA    60    60    15    60    60
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...