Как импортировать таблицу Matlab (структура «ячейка») в R-фрейм данных, сохраняя при этом правильную структуру / порядок? - PullRequest
1 голос
/ 16 октября 2019

Проблема

Документация для функции readMat() гласит: «Для формата MAT v5 структуры ячеек считываются в R как структура списка.»

Это создает проблему для меняпоскольку я не могу преобразовать его обратно в исходную структуру таблицы из объекта списка. В исходных файлах, которые я унаследовал, каждая строка (а не столбец) представляет ответы на разные вопросники (строка1 = вопросник1, строка2 = вопросник2 и т. Д.), Но способ readMat() создает список по вертикали (по столбцам), поэтому мойВсе элементы анкеты в основном все перепутали.

Код для желаемого результата

Вот код для воспроизведения упрощенного примера желаемого результата и внешнего вида файла в структуре Matlab cell:

list1 <- list("2",   "34", "17", NA,  NA,  NA)
list2 <- list("32",  "43", NA,   NA,  NA,  NA)
list3 <- list("C",   "D",  "A",  "F", "G", "I")
list4 <- list("455", NA,   NA,   NA,  NA,  NA)
df <- data.frame()
df <- rbind(df,list1,list2,list3,list4)
colnames(df) <- NULL
rownames(df) <- NULL
df

Это выводит следующее ( Желаемая выходная / оригинальная структура MATLAB ):

1   2   34   17 <NA> <NA> <NA>
2  32   43 <NA> <NA> <NA> <NA>
3   C    D    A    F    G    I
4 455 <NA> <NA> <NA> <NA> <NA>

Таким образом, я могу выбирать по строке, вместо того, чтобы иметь беспорядочный порядокнаблюдения. Обратите внимание, что я заменил значения NULL на NA для этого примера, иначе у меня возникла ошибка при создании фрейма данных.

Код для нежелательного вывода

Однако для воспроизведения результатаимпортируя в R из Matlab с readMat() нам нужен здоровенный код, подобный этому:

list1 <- list(matrix("2"))
list2 <- list(matrix("32"))
list3 <- list(matrix("C"))
list4 <- list(matrix("455"))
list5 <- list(matrix("34"))
list6 <- list(matrix("43"))
list7 <- list(matrix("D"))
list8 <- NULL
list9 <- list(matrix("17"))
list10 <- NULL
list11 <- list(matrix("A"))
list12 <- NULL
list13 <- NULL
list14 <- NULL
list15 <- list(matrix("F"))
list16 <- NULL
list17 <- NULL
list18 <- NULL
list19 <- list(matrix("G"))
list20 <- NULL
list21 <- NULL
list22 <- NULL
list23 <- list(matrix("I"))
list24 <- NULL
(mylist <- list(list1, list2, list3, list4, list5, 
                list6, list7, list8, list9, list10,
                list11, list12, list13, list14, list15,
                list16, list17, list18, list19, list20,
                list21, list22, list23, list24))

, который выводит следующее:

[[1]]
[[1]][[1]]
     [,1]
[1,] "2" 


[[2]]
[[2]][[1]]
     [,1]
[1,] "32"


[[3]]
[[3]][[1]]
     [,1]
[1,] "C" 


[[4]]
[[4]][[1]]
     [,1] 
[1,] "455"


[[5]]
[[5]][[1]]
     [,1]
[1,] "34"


[[6]]
[[6]][[1]]
     [,1]
[1,] "43"


[[7]]
[[7]][[1]]
     [,1]
[1,] "D" 


[[8]]
NULL

[[9]]
[[9]][[1]]
     [,1]
[1,] "17"


[[10]]
NULL

[[11]]
[[11]][[1]]
     [,1]
[1,] "A" 


[[12]]
NULL

[[13]]
NULL

[[14]]
NULL

[[15]]
[[15]][[1]]
     [,1]
[1,] "F" 


[[16]]
NULL

[[17]]
NULL

[[18]]
NULL

[[19]]
[[19]][[1]]
     [,1]
[1,] "G" 


[[20]]
NULL

[[21]]
NULL

[[22]]
NULL

[[23]]
[[23]][[1]]
     [,1]
[1,] "I" 


[[24]]
NULL

Так что в других темах большинство людейсказал unlist , но отсутствие моего списка не позволяет мне, например, выбирать вопросники по строкам (тем более, что значения NULL не сохраняются в измерениях при выводе из списка):

unlist(mylist)
[1] "2"   "32"  "C"   "455" "34"  "43"  "D"   "17"  "A"   "F"   "G"   "I"  

Вы можете видеть, что он более аккуратный, но элементы расположены не в правильном порядке, поэтому трудно поместить их обратно во фрейм данных. Некоторые говорили, что превращаются в матрицу ... которая на самом деле не решает проблему:

matrix(unlist(mylist))    
     [,1] 
 [1,] "2"  
 [2,] "32" 
 [3,] "C"  
 [4,] "455"
 [5,] "34" 
 [6,] "43" 
 [7,] "D"  
 [8,] "17" 
 [9,] "A"  
[10,] "F"  
[11,] "G"  
[12,] "I"  

Я пробовал другие решения из потоков безрезультатно, например:

do.call(rbind.data.frame, mylist) # doesn't work
as.data.frame(matrix(unlist(mylist),nrow=length(mylist),byrow=TRUE)) # doesn't work

Вот несколько связанных тем: 1 , 2 , 3 , 4 , 5 , 6 , 7 и 8 .

Вопрос

  1. Почему для readMat() необходимоимпортировать MAT v5 форматировать структуры ячеек в виде списков, а не фреймов данных (это избавило бы нас от многих проблем)?

  2. Я ищу решение в идеале в базе R для преобразованиясписок readMat() для фрейма данных, который я мог бы автоматизировать, если бы у меня было тысячи таких файлов, которые я не собираюсь редактировать, реструктурировать или сохранять в другом формате по отдельности в Matlab, и предполагая количество и местоположение *Различаются значения 1078 *, а также длина каждой строки (некоторые анкеты содержат больше элементов, чем другие). Спасибо!

1 Ответ

0 голосов
/ 16 октября 2019

Я до сих пор не знаю, почему MAT v5 нужно импортировать таблицы в списки, но я неожиданно нашел решение!

Функция ниже легко извлечет определенную строку из списка этого типа, где list - это ваш список, row - это строка, которую вы хотите извлечь, а nrow - это общее количество строк (при условии, что вы знаете эти детали):

matlab.row <- function(list,row,nrow) {
  unlist(list[seq(row, length(list), nrow)]) # This will take every nth element starting from desired row
}

matlab.row(mylist,1,4)
"2"  "34" "17"
matlab.row(mylist,2,4)
"32" "43"
matlab.row(mylist,3,4)
"C" "D" "A" "F" "G" "I"
matlab.row(mylist,4,4)
"455"

Чтобы получитьполный кадр данных, мне пришлось еще немного подправить функцию, где list - ваш список, max.len - длина самой длинной строки (максимальное количество элементов), а nrow - ваше общее количество строк:

matlab.df <- function(list,max.len,nrow) {
  matlab.row <- function(list,row,nrow) { # We reuse the function we just made earlier
    unlist(list[seq(row, length(list), nrow)])
  }
  listA <- vector('list', nrow) # Precreates list
  for (i in 1:nrow) {
    listA[i] <- list(c(matlab.row(list,i,nrow), # Combines output from last function to NAs on next line
                  rep(NA, max.len - length(matlab.row(list,i,nrow))))) # Fills the remaining columns with NAs (very important part!)
  }
  df <- do.call(rbind,listA) # Binds elements together from the list we created as rows
  df # Prints dataframe
}

matlab.df(list = mylist, max.len = 6, nrow = 4)
     [,1]  [,2] [,3] [,4] [,5] [,6]
[1,] "2"   "34" "17" NA   NA   NA  
[2,] "32"  "43" NA   NA   NA   NA  
[3,] "C"   "D"  "A"  "F"  "G"  "I" 
[4,] "455" NA   NA   NA   NA   NA  

Я нашел решение благодаря комбинации следующих потоков: 1 , 2 , 3 и 4 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...