1 如何做数据转换,例如Excel文件转换为csv文件?
我不会写很长的介绍,我们都知道Excel在商业界广泛应用,它拥有大量非常好的特性,特别是对于那些不懂得编写程序的商业从业者。但是,如果Excel提供的功能不能满足个人意愿,那就会比较麻烦。通常,人们把Excel当做一个汇报的工具,虽然它实际上不是这样的工具。他们制作非常精致复杂的电子表格,以便人们阅读,却不能被其它工具导入。
在这片博客帖子中(可能是一系列的一部分),我会向你展示如何从这样:
转换为这样:
你可以在这里找到我使用的数据。点击“Time use”并下载工作本。
Excel工作本包含了几个表格(法语版以及英语版),
表格的内容是卢森堡居民从周一到周日使用时间的情况。比如,职场人士在工作日平均花费八小时的睡眠时间,而在周六为八小时四十五分钟。
在你看到的电子表格中,每个sheet包含了多个表格,而每个表格又包含很多小标题,表格一个紧挨一个。尝试采用
readxl::read_excel()
只能产生一个奇怪的东西。
这就是
{tidyxl}
出现的原因。现在采用
{tidyxl}
导入工作本。
1
看一下发生了什么:
1head(time_use_xl)
1
正如你看到的那样,sheet被导入了,但结果并不是希望的那样。实际上,time_use_xl
是一个tibble
的对象,其中的每一行都是Excel表中的一个小单元。这看起来可能非常难以处理,但是你将看到它确实可以把事情简单化。
我只想使用英文版的sheets,所以我采用下面的编码忽略法语版的sheets。
1sheets "time-use.xlsx") %>%
同样,有一个sheet整合了工作日以及周末的结果,我也忽略了。
现在,为了提取每个sheet中的表格,我编写以下函数:
1extract_data function(sheet){
让我们一步步学习并看看它到底如何工作的。首先,有一个关键点sheet
。这个函数将会与工作本中每一个sheet配对。接着,我写的第一个区间用于提取活动:
1 activities %
我只保留了第二列(filter(col == 2)
),col
是tibble
中的colunmn
,如果你翻开工作本,你将发现活动位于第二列,或者B列。接着,我选择两列,row
和character
列,row
不言自明,character
实际上包含了任何出现在单元里面的东西。然后,我保留6到58行,因为我对它们感兴趣,其余部分要么是空的,要么不需要。最后,我把character
列重新命名为activities并且删除了row
的列。
第二个区域:
1 cols_to_extract %
返回了我想要提取列的序号。我只关心完成活动的人群,因此采用filter()
里面的grepl()
。我放置这些列,并且使用pull()
……把它们拉出数据框!cols_to_extract
是我想要保留的一个完美的原子矢量列。
在第三个区间,我提取了头标签
1headers_pos 1
为什么-1
?这是因为当你翻看Excel,你会发现头标签是在列标签“People who completed the activity”的前一列。比如G列,有“People who completed the activity”以及在F列有头标签“Male”。
现在我要提取头标签:
1 headers %
头标签总是在第三行,虽然在不同列,因此采用col %in% headers_pos
。接着通过pull(character)
从单元里抓取数值。因此我的headers
对象将会是一个原子矢量,包含“All”,“Male”,“Female”,“10 - 19 years”等,都在第三行。
最后的一个区域,提取了数据:
1 cols_to_extract %>%
cols_to_extract
是我感兴趣的列所在位置的一个矢量。比如“4”,“7”,“10”等。我把这个矢量与sheet配对,返回了一系列数据框。接着我使用select()(什么在map()里面……为什么?因为输入的参数是一系列的数据框)。因此对于目录里面的每个数据框,我选择了sheet
,address
,row
,col
以及character
列。接着采用filter()
保留6到58行。然后,选择character
列,它包含单元中的文本信息。随后,使用map2()
,在headers
对象中添加数值作为新列,命名为population
。接着,将activities
列添加进数据框,并把所有的行放在一起。
是时候运行该函数了!看一下结果:
1clean_data %
1
我用tibble
操作目录中的sheets,tibble是用readxl
导入的,使用set_names
命名我的目录(其实没必要,只是我想表示一下,可能你对此有兴趣),然后把我的函数应用到这个结果上。我可以在这里停下,但我接着增加了新的一列到每个数据框中,包含了数据被测量的日期信息,将每行组装起来,重新排序每列。完成!
现在,我怎么制作出这个函数?我没有借用一个函数开始。开始时,我写一些代码只针对sheet中每一个表格我需要的部分。只有当我写出了一些可以操作的代码,我才开始把它推广应用到多个表格,最后到多个sheets。大部分的时间都用在了尝试寻找Excel表中的模式,以便于可以写进我的函数里面(比如发现了我需要的头标签总是在感兴趣所在列的前一列)。我建议,在编写程序时,先从处理一个小问题开始,把代码包装进函数,然后把函数应用到一系列的元素中!
作者:Bruno Rodrigues