Как импортировать многофайловые данные .xlsx в один фрейм данных R без уровней?

Я пытаюсь извлечь данные каждой компании из некоторых бесплатных наборов данных NASDAQ 100 Twitter, доступных здесь. Конечной целью после создания и курирования является проведение некоторых экспериментов по моделированию с фреймом данных. Основная форма данных, к которой я стремлюсь:

ATVI  49.02   0.44   0.91   7193022   .3 
ADBE  119.91  0.31   0.26   1984225   .1 
AKAM  64.2    0.65   1.02   1336622   .1 
ALXN  126.55  0.86   0.67   2182253   .2
GOOG  838.68  3.31   0.4    1261517  1.0 
AMZN  853     2.5    0.29   2048187  1.0

Для каждой компании есть шесть файлов .xlsx (разархивированных в отдельные каталоги), каждый файл Excel с несколькими рабочими листами внутри. Сейчас я просто пытаюсь извлечь первый рабочий лист из каждой из шести электронных таблиц Excel для каждой компании. Все эти рабочие листы имеют два столбца с разным количеством строк, а метки данных находятся в разных строках, например. файл 1, компания 1:

Keyword             $AAPL -
Total tweets        166631
Total audience      221363515
Contributors        42738
Original tweets     91614
Replies             4964
RTs                 70053
Images and links    43361

файл 2, компания 1:

Keyword                        $AAPL -
Total audience                 221363515
Contributors                   42738
Total tweets                   166631
Total potential impressions    1.250.920.501
Measured data from             2016-04-02 18:06
Measured data to               2016-06-15 12:23
Tweets per contributor         3,90
Impressions / Audience         5,65
Measured time in seconds       6373058
Measured time in minutes       106218
Measured time in hours         1770
Measured time in days          74
Tweets per second              0.026146161
Tweets per minute              1.568769655
Tweets per hour                94.1261793
Tweets per day                 2259.028303

Я пытаюсь реализовать readxl, как это предлагается в этом post, а затем поместите данные каждой компании в строку фрейма данных [ниже]. Прямо сейчас я устанавливаю первый путь в качестве своего каталога, а затем запускаю код, затем устанавливаю второй путь и запускаю его снова, чтобы добавить новую строку (я знаю, что это не оптимально, см. ниже).

library(readxl)

#create empty dataframe to assemble all the rows
cdf <- data.frame()

#setwd('...\\NASDAQ_100\\aal_2016_06_15> cdf data frame with 0 columns and 0 rows01_41')
#setwd('...\\NASDAQ_100\\aapl_2016_06_15_14_30_09')

#constructing list of all .xlsx files in current directory
file.list <- list.files(pattern='*.xlsx')

#using read_excel function to read each file in list and put in a dataframe of lists 
df.list <- lapply(file.list, read_excel)

#converting the dataframe of lists to a 77x2 dataframe
df <- as.data.frame(do.call(rbind, df.list),stringsAsFactors=FALSE)

#transposing the dataframe to prepare to stack multiple companies data in single dataframe
df <- t(df)

#making sure that the dataframe entry values are numeric
df <- transform(df,as.numeric)

#appending the 2nd row with the actual data into the dataframe that will have all companies' data
cdf <- rbind(cdf,df[2,])

Пример вывода:

> cdf[,1:8]
            X1        X2    X3    X4   X5    X6    X7        X8
$AAL      6507  14432722  1645  5211  459   837   938  14432722
$AAPL - 166631 221363515 42738 91614 4964 70053 43361 221363515

После проверки я обнаружил, что в моих столбцах есть уровни, которые я собрал из разных других сообщений, из-за того, как я импортировал данные, и поэтому я пытался добавить stringsAsFactors=FALSE к as.data.frame, но ясно, что это не решение:

> cdf[,2]
     $AAL   $AAPL - 
 14432722 221363515 
Levels: 14432722 Total audience 221363515

Согласно документации, это не аргумент для read_excel. Есть ли способ по-прежнему использовать его, но избегать этих уровней?

Как только я разобрался с этим, я надеюсь получить это в базовом цикле for для просмотра всех разархивированных подкаталогов:

dir.list <- list.dirs(recursive = F)

for (subdir in dir.list) {

  file.list <- list.files(pattern='*.xlsx')

  df.list <- lapply(file.list, read_excel)

  df <- as.data.frame(do.call(rbind, df.list),stringsAsFactors=FALSE)

  df <- t(df)

  df <- transform(df,as.numeric)

  cdf <- rbind(cdf,df[2,])

}

Но это дает > cdf data frame with 0 columns and 0 rows? Я знаю, что ни один из кодов не является элегантным или компактным (и что rbind не рекомендуется в циклах for), но это то, что мне удалось собрать воедино. Я очень восприимчив к исправлениям стиля и альтернативным методам, но было бы очень полезно, если бы их контекст был объяснен в рамках общей проблемы/решения, описанного здесь (т.е.: не просто «использовать пакет xyz» или «прочитать ldply() документацию").

Спасибо,


person xq1515426    schedule 12.03.2017    source источник


Ответы (2)


Данные в файлах .xlsx хранятся в структуре ключа (столбец 1) и значения (столбец 2). Я бы использовал readxl и data.table для чтения данных и первоначально сохранял их в длинном формате ключ/значение (с третьим столбцом, указывающим компанию). Затем я бы преобразовал (dcast) длинный формат в широкий формат, чтобы каждый ключ получил свой собственный столбец:

library(readxl)
library(data.table)

# Get list of files
file.list <- list.files(path = ".", pattern = "*.xlsx")

# Iterate over files
dt_list <- lapply(seq_along(file.list), function(x) {
  # Read sheet 1 as data.table
  dt <- data.table(read_excel(file.list[x], sheet = 1))
  # Get company based on name of second column
  company <- gsub(colnames(dt)[2], pattern = "[^A-Z]*", replacement = "")
  # Set company and file_name (optional for debugging)
  dt[, ":="(company = company, file_name = file.list[x])]
  setnames(dt, c("key", "value", "company", "file_name"))
  dt
})
dt <- rbindlist(dt_list, use.names = TRUE)

# Get rid of file_name and remove duplicates
dt[, file_name := NULL]
dt <- unique(dt)

# Optional filtering on key
# dt <- dt[key %in% c("Total tweets", "Total audience")]

# Use dcast to make wide format table with one row per company
dt_wide <- dcast(dt, formula = company~key)

Содержимое dt_wide (с AAPL и ATVI):

    company Average contributor followers Average contributor following Contributor followers median ...
 1:    AAPL                       5197,58                        832,06                       141,00 ...
 2:    ATVI                       9769,01                       1389,17                       562,00 ...

Вы можете преобразовать dt_wide в стандартный data.frame с помощью df <- as.data.frame(dt_wide)

person Kristoffer Winther Balling    schedule 13.03.2017
comment
Большое спасибо, что нашли дополнительное время. У меня мало опыта использования data.table, и я даже не слышал о dcast раньше. - person xq1515426; 14.03.2017

Я предполагаю, что ваш df.list содержит data.frames с факторами, а не строками, и это может быть причиной проблем в последующем rbind. Ты можешь попробовать:

df.list <- lapply(file.list, function(x) {
             as.data.frame(read_excel(x), stringsAsFactors=FALSE)
           })

Таким образом, data.frames в df.list не должны содержать факторы.

person Kristoffer Winther Balling    schedule 12.03.2017
comment
Я попробовал это предложение и соответственно изменил df <- do.call(rbind, df.list) и попытался сохранить его, как указано выше, но оба по-прежнему выводят: > cdf[,2] $AAL $AAPL - 14432722 221363515 Levels: 14432722 Total audience 221363515 - person xq1515426; 12.03.2017
comment
Хорошо. Я попытаюсь получить файлы .xlsx и выполнить отладку в своей системе. - person Kristoffer Winther Balling; 12.03.2017