Loading...
墨滴

yuanzhoulvpi

2021/07/10  阅读:28  主题:橙心

R高效处理数据_1

R高效处理excel数据

  1. 如何批量处理excel文件,对excel文件进行汇总。
  2. 如果excel的表头有两行,如何进行处理。

背景

不管是在工作中还是在学习中,经常会遇到一些奇奇怪怪的数据,比如下面的excel数据有两行:

第一行是表的表头;第二行是别的信息,从这个excel里面可以看出来,第二行是这一列的介绍。 可是我们不想要第二行,因为在导入数据的时候,第二行是文本信息会影响每一列的数据结构,比如说第一列本来是数值型的,结果因为表头的第二行是文本,将所有数值型的都转换为了字符串型,这肯定影响我们后续的处理数据流程。

还有一个问题,就是说我们这个文件夹下,有很多这样的excel数据,我需要将这些数据都汇总到一个大表里面,我应该怎么做?

解决问题

创建demo数据

首先,我们为了复现这样的问题,我们需要一些demo数据来帮助我们理解。接下来代码是帮助生成一个all_stickes_0710文件夹,然后在这个文件夹下面,创建很多个小的excel文件。

代码的大概意思是说从一个有着双表头的数据中提取数据,然后将随机提取的数据保存到excel文件中,中间只是改变excel的数据行数和位置,保留excel的原始的两个表头。(其实代码里面有几个有趣的点,但是这里不做介绍)

代码如下:

library(tidyverse)
library(readxl)
library(writexl)



# part1 -------------------------------------------------------------------

all_stickers <- read_tsv("https://dataverse.harvard.edu/api/access/datafile/2712105")


excel_name_dir <- "all_stickes_0710"

if (file.exists(excel_name_dir)) {
  unlink(x = excel_name_dir, recursive = TRUE)
  dir.create(excel_name_dir)
else {
  dir.create(excel_name_dir)
}


random_id <- sample(x = 2:nrow(all_stickers), size = nrow(all_stickers)-1)

seq_id <- seq(from=1,to = nrow(all_stickers)-1, by = 20)

for (temp_seqid in seq_id) {
  tempdata <- all_stickers %>% slice(c(1,random_id[temp_seqid:(temp_seqid+20-1)]))
  write_xlsx(x = tempdata, path = glue::glue("{excel_name_dir}/stickes_{temp_seqid}.xlsx"))
}

上面代码运行结束以后,会在你的工作目录中创建一个文件夹all_stickes_0710,这个文件夹all_stickes_0710里面保存了很多子excel。(如果不知道当前的工作目录是什么位置,使用这个命令查看:getwd()

提取单个数据

我们顺着上面的工作目录,然后就可以找到📁all_stickes_0710

其实提取单个文件,然后将第二行不需要的表头丢掉,然后将数据保存起来也是非常简单,完整的代码如下:


# part2 -------------------------------------------------------------------

get_excel_file_name <- list.files(path = excel_name_dir, pattern = '*.xlsx')
get_excel_file_name

# test part

temp_test_excel_file_name <- get_excel_file_name[1]

temp_test_excel_file_location <- glue::glue("{excel_name_dir}/{temp_test_excel_file_name}")
temp_test_excel_file_colname <- read_xlsx(path = temp_test_excel_file_location, n_max = 1) %>% colnames()

temp_test_excel_file_result <- read_xlsx(path = temp_test_excel_file_location, skip = 2, col_names = temp_test_excel_file_colname) %>% type_convert()
temp_test_excel_file_result
# create a function

get_clean_data <- function(excel_file_name) {
  
  temp_excel_file_location <- glue::glue("{excel_name_dir}/{excel_file_name}")
  temp_excel_file_colname <- read_xlsx(path = temp_excel_file_location, n_max = 1) %>% colnames()
  
  temp_excel_file_result <- read_xlsx(path = temp_excel_file_location, skip = 2, col_names = temp_excel_file_colname) %>% type_convert()
  temp_excel_file_result['from_excel'] <- excel_file_name
  return(temp_excel_file_result)
  
}


get_clean_data(excel_file_name = get_excel_file_name[2])


在上面的代码中:

  1. get_excel_file_name这句话对应的变量意思是:获得这个文件夹下所有以xlsx结尾的文件名字,是一个文本向量。
  2. 虽然我们目前可以获得这个文件夹下面的excel名字,但是机器不知道这些文件夹在哪个文件夹下,所有我们需要将文件夹名字和excel文件名按照路径的方式拼接起来,那么temp_test_excel_file_location这句话就是实现这个功能。
  3. 先提取表头,然后再提取数据部分(强调分开提取)
  4. 当我们在使用read_xlsx函数的时候,我们读取的是一个excel文件,但是我们只是希望读取这个文件的第一行,因为读那么多没有什么用,实际上只是想要这个文件的有用的表头内容罢了(提取表头的第一行,不要表头的第二行)。所以说temp_test_excel_file_colname这行代码的意思就是告诉R,说我只是想要这个表的有用的那行表头,然后将表头提取出来。
  5. 在4的基础上,我们得到了我们想要的表头,不需要的表头已经被我们丢弃了。然后我们再次读取这个文件,这次是读取这个excel文件的数据部分,因此我们要将这个excel文件的前两行内容(分别是表头的第一行和表头的第二行)丢弃掉,所以你在temp_test_excel_file_result这句话里面可以看到skip=2。但是丢弃丢弃表头的后果就是意味着我们还要再传递一个指定的表头,所以你在temp_test_excel_file_result这句话里面可以看到col_names = temp_test_excel_file_colname。另外可能有的列明明是数值,但是还是被处理为文本,因此我们再使用type_convert()函数处理一下。
  6. 上面的步骤了解清楚以后,将这些步骤打包成一个函数,这个函数只是需要传递一个excel文件名,然后就可以输出这个文件名对应的数据。这也就是get_clean_data函数内容了。

批量处理多个文件然后合并

在上面的步骤都清楚的情况下,这部分就已经很简单了,代码如下:

# part3 -------------------------------------------------------------------

big_final_data <- do.call(bind_rows, lapply(X = get_excel_file_name, FUN = get_clean_data))
big_final_data %>% dim()
  1. lapply见一个列表的文件名传递到get_clean_data函数中,还是会得到一串列表,只不过这个列表里面每一个都是一个数据框。
  2. do.call函数将上面lapply返回的结果按照行合并进行合并。最终得到一个大的数据框。

总结

  1. 处理多个表头的数据的时候,有这个表头和数据内容分开提取想法。然后找到相关的函数进行使用就行。
  2. 有批处理思想,善于使用列表思想。在刚开始学习R的时候,感觉列表有啥用呢,提取起来这么麻烦,但是越到后来,越来越感觉列表这个东西用起来真的舒服,不管是在R还是在python中。列表作为数据处理的桥梁,结合对应的函数,用起来是越用越幸福。
  3. 很多东西都是变量,我们如何将一系列变量转换成一个固定的对象,这个固定的对象包含很多变化的变量,那么我们只要这个固定的对象做处理,不管内部变量怎么变化,我们写的函数都能处理,也就是说在处理数据中,有全局意思,掌握哪些数据是可变的,哪些数据是不可变的,如何使用不可变的变量去控制可变的内容,那么代码写起来就是非常少。

yuanzhoulvpi

2021/07/10  阅读:28  主题:橙心

作者介绍

yuanzhoulvpi