Автоматическое получение типов столбцов Excel

У меня есть файл excel с несколькими листами, каждый с несколькими столбцами, поэтому я бы хотел не указывать тип столбца отдельно, а автоматически. Я хочу прочитать их как stringsAsFactors= FALSE, потому что он правильно интерпретирует тип столбца. В моем текущем методе ширина столбца "0,492 ± 0,6" интерпретируется как число, возвращающая NA ", потому что" опция stringsAsFactors недоступна в read_excel. Итак, я пишу обходной путь, который работает более или менее хорошо, но я не могу использовать его в реальной жизни, потому что мне не разрешено создавать новый файл. Примечание. Мне нужны другие столбцы как числа или целые числа, а также другие, которые имеют только текст в качестве символов, как stringsAsFactors в моем примере read.csv.

library(readxl)
file= "myfile.xlsx"
firstread<-read_excel(file, sheet = "mysheet", col_names = TRUE, na = "", skip = 0)
#firstread has the problem of the a column with "0.492 ± 0.6", 
#being interpreted as number (returns NA)
colna<-colnames(firstread)

# read every column as character
colnumt<-ncol(firstread)
textcol<-rep("text", colnumt)
secondreadchar<-read_excel(file, sheet = "mysheet", col_names = TRUE, 
col_types = textcol, na = "", skip = 0)
# another column, with the number 0.532, is now 0.5319999999999999 
# and several other similar cases.

# read again with stringsAsFactors 
# critical step, in real life, I "cannot" write a csv file.
write.csv(secondreadchar, "allcharac.txt", row.names = FALSE)
stringsasfactor<-read.csv("allcharac.txt", stringsAsFactors = FALSE)
colnames(stringsasfactor)<-colna
# column with "0.492 ± 0.6" now is character, as desired, others numeric as desired as well

Ответ 1

Вот script, который импортирует все данные в ваш файл excel. Он помещает данные каждого листа в list, называемый dfs:

library(readxl)

# Get all the sheets
all_sheets <- excel_sheets("myfile.xlsx")

# Loop through the sheet names and get the data in each sheet
dfs <- lapply(all_sheets, function(x) {

  #Get the number of column in current sheet
  col_num <- NCOL(read_excel(path = "myfile.xlsx", sheet = x))

  # Get the dataframe with columns as text
  df <- read_excel(path = "myfile.xlsx", sheet = x, col_types = rep('text',col_num))

  # Convert to data.frame
  df <- as.data.frame(df, stringsAsFactors = FALSE)

  # Get numeric fields by trying to convert them into
  # numeric values. If it returns NA then not a numeric field.
  # Otherwise numeric.
  cond <- apply(df, 2, function(x) {
    x <- x[!is.na(x)]
    all(suppressWarnings(!is.na(as.numeric(x))))
  })
  numeric_cols <- names(df)[cond]
  df[,numeric_cols] <- sapply(df[,numeric_cols], as.numeric)

  # Return df in desired format
  df
})

# Just for convenience in order to remember
# which sheet is associated with which dataframe
names(dfs) <- all_sheets

Процесс выполняется следующим образом:

Сначала вы получаете все листы в файле с помощью excel_sheets, а затем пронумеруйте имена листов для создания данных. Для каждого из этих фреймов данных вы сначала импортируете данные как text, установив параметр col_types в text. После того как вы получили столбцы dataframe как текст, вы можете преобразовать структуру из tibble в data.frame. После этого вы найдете столбцы, которые на самом деле являются числовыми столбцами и преобразуют их в числовые значения.

Edit:

По состоянию на конец апреля была выпущена новая версия readxl, а функция read_excel получила два усовершенствования, относящихся к этому вопросу. Во-первых, вы можете заставить функцию угадывать типы столбцов для вас с аргументом "угадать", предоставленным параметру col_types. Второе улучшение (следствие первого) заключается в том, что параметр guess_max добавлен в функцию read_excel. Этот новый параметр позволяет вам установить количество строк, используемых для угадывания типов столбцов. По существу, то, что я написал выше, можно сократить следующим образом:

library(readxl)

# Get all the sheets
all_sheets <- excel_sheets("myfile.xlsx")

dfs <- lapply(all_sheets, function(sheetname) {
    suppressWarnings(read_excel(path = "myfile.xlsx", 
                                sheet = sheetname, 
                                col_types = 'guess', 
                                guess_max = Inf))
})

# Just for convenience in order to remember
# which sheet is associated with which dataframe
names(dfs) <- all_sheets

Я бы рекомендовал вам обновить readxl до последней версии, чтобы сократить ваш script и, как результат, избежать возможных неприятностей.

Надеюсь, это поможет.