일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- spring MVC(모델2)방식
- Python
- Websocket
- 이력서
- 과학백과사전
- 게시판 만들기
- 토픽추출
- RESFUL
- test
- oracle
- jsp 파일 설정
- tomoto
- 파이썬
- (깃)git bash
- r
- word2vec
- 크롤링
- 방식으로 텍스트
- db
- pytorch
- Gmarket
- 코사인 유사도
- Topics
- lda
- 자바
- 네이버뉴스
- 지마켓
- java
- 幼稚园杀手(유치원킬러)
- mysql
- Today
- Total
무회blog
使用,Pandas,进行大型,Excel,文件处理 본문
使用Pandas进行大型Excel文件处理
Python部落(www.freelycode.com)组织翻译, 禁止转载
今天我们将学习如何使用Pandas进行大文件处理,重点关注Excel文件的读取解析及对原始数据进行抽取加工。
本教程采用的Python(已通过64位版本的v2.7.9和v3.4.3的测试),Pandas (v0.16.1),和XlsxWriter(v0.7.3)。 我们建议使用Anaconda版本快速上手,因为它预装了所有需要的依赖库。
本文是由Python For Engineers的创始人Shantnu Tiwari 和 Real Python 上有趣的小伙伴们合作完成。
读取文件
我们要处理的第一份文件,是在1979-2004年间在英国发生的所有车祸的汇总数据中,抽取2000年发生在伦敦的所有事故数据。
Excel
首先,从data.gov.uk网站上下载源文件,并解压ZIP包。 然后找到Accidents7904.csv,并在Excel中打开。请注意,如果没有足够的内存,这很可能使您的计算机程序崩溃。
发生了什么事情呢?
你应该会看到一个“文件未完全加载”的错误,因为Excel一次只能处理一个百万行。 我们通过LibreOffice中进行测试,并收到了类似的错误- “数据不能被完全加载,因为已经超过了每个sheet表能够加载的最大行数。”
为了解决这个问题,我们需要使用Pandas打开这个文件。 在我们开始之前,可以在Github上获取最新源代码 。
Pandas
使用 virtualenv沙盒环境,创建一个新的工程目录,然后开始安装Pandas:
$ pip install pandas==0.16.1
现在,可以构建我们的脚本。创建一个名为pandas_accidents.py,然后添加以下代码:
import pandas as pd
# Read the file
data = pd.read_csv("Accidents7904.csv", low_memory=False)
# Output the number of rows
print("Total rows: {0}".format(len(data)))
# See which headers are available
print(list(data))
在这里,我们导入了Pandas模块用户读取文件--这可能需要一些时间,主要取决于你的系统拥有有多少内存 ,并且输出文件中所有行的数据具有和现有的表头数据(例如,列标题)。
当运行结束,你将看到:
总行数: 6224198
['\xef\xbb\xbfAccident_Index', 'Location_Easting_OSGR', 'Location_Northing_OSGR',
'Longitude', 'Latitude', 'Police_Force', 'Accident_Severity', 'Number_of_Vehicles',
'Number_of_Casualties', 'Date', 'Day_of_Week', 'Time', 'Local_Authority_(District)',
'Local_Authority_(Highway)', '1st_Road_Class', '1st_Road_Number', 'Road_Type',
'Speed_limit', 'Junction_Detail', 'Junction_Control', '2nd_Road_Class',
'2nd_Road_Number', 'Pedestrian_Crossing-Human_Control',
'Pedestrian_Crossing-Physical_Facilities', 'Light_Conditions', 'Weather_Conditions',
'Road_Surface_Conditions', 'Special_Conditions_at_Site', 'Carriageway_Hazards',
'Urban_or_Rural_Area', 'Did_Police_Officer_Attend_Scene_of_Accident',
'LSOA_of_Accident_Location']
哇,超过六百万行的数据! 难怪Excel抑郁了。现在将注意力转移到头部,特别是第一个:
'\xef\xbb\xbfAccident_Index',
这应该读作Accident_Index,那么开头处额外的\xef\xbb\xbf是什么呢? 好了,\x实际上意味着该值是十六进制的 ,这是一个字节顺序标记 ,表示该文本为Unicode。
为何这点对我们如此重要?
你不能假设你读取的文件是无干扰因素的。它们可能包含像这样多余的标记符号,从而使你的脚本无法正常运行。
如果一个文件是无干扰数据,那这个文件就是个好文件 - 但很多文件有丢失数据,或在内部数据格式上不一致,等等……。因此,任何时候你有一个文件来分析,你必须做的第一件事就是清理数据。要进行多少清理呢?要足以让你能够做一些分析。 遵循KISS原则。
你可能需要什么样的清理呢?
修复日期/时间,同样的文件中可能包含不同的日期格式,如美式(MM-DD-YY)或欧式(DD-MM-YY)的格式。 这些都需要归纳成一个共同的格式。
删除所有的空值。该文件可能有空白列和(或)行,在Pandas这些这将显示NaN(非数字)。 Pandas提供了一种简单的方法来移除空值:dropna()函数。 我们看到了一个这样的例子last blog post。
删除那些用自己的方式进入数据的任何垃圾值,这些都是无意义的垃圾值(像之前我们看到的字节顺序标记)。 但是,有时我们可以解决它们。例如在一个年龄被作为一个浮点数输入的(误操作)的数据集中, 用int()函数,则可以用来确保所有年龄段都是整数格式。
分析数据
你们当中知道SQL的小伙伴,可以使用SELECT,WHERE,AND / OR语句,使用不同的关键词来缩小搜索范围。我们可以通过Pandas做到同样的效果,并且是对程序员来说更友好的方式。
让我们开始吧,首先我们找到所有发生在星期天的事故。通过查看表头,我们将使用一个叫做Day_of_Weeks字段。
在你下载的ZIP文件,有一个Road-Accident-Safety-Data-Guide-1979-2004.xls文件,这个文件中包含我们代码所需要的额外的信息。如果你打开它,你会看到星期天的代号为1 。
print("\nAccidents")
print("-----------")
# Accidents which happened on a Sunday
accidents_sunday = data[data.Day_of_Week == 1]
print("Accidents which happened on a Sunday: {0}".format(
len(accidents_sunday)))
这是多么简单。
在这里,我们锁定了Day_of_Weeks字段并返回一个有过滤条件day of week == 1的DataFrame表数据 。
当你运行代码时,应该看到:
Accidents
-----------
Accidents which happened on a Sunday: 693847
正如你所看到的,有693847事故发生在星期天。
让我们把我们的查询做的更加复杂:找出发生在周日,涉及超过20辆汽车的所有事故:
# Accidents which happened on a Sunday, > 20 cars
accidents_sunday_twenty_cars = data[
(data.Day_of_Week == 1) & (data.Number_of_Vehicles > 20)]
print("Accidents which happened on a Sunday involving > 20 cars: {0}".format(
len(accidents_sunday_twenty_cars)))
运行该脚本。 现在我们有10起事故:
Accidents
-----------
Accidents which happened on a Sunday: 693847
Accidents which happened on a Sunday involving > 20 cars: 10
让我们添加另一个条件 - 天气。
打开Road-Accident-Safety-Data-Guide-1979-2004.xls,并转到天气Sheet表。 你会看到代号2表示,“下雨没有强风”。
以下是我们的查询:
# Accidents which happened on a Sunday, > 20 cars, in the rain
accidents_sunday_twenty_cars_rain = data[
(data.Day_of_Week == 1) & (data.Number_of_Vehicles > 20) &
(data.Weather_Conditions == 2)]
print("Accidents which happened on a Sunday involving > 20 cars in the rain: {0}".format(
len(accidents_sunday_twenty_cars_rain)))
因此,有四个事故发生在下雨的周日,涉及超过20辆汽车:
Accidents
-----------
Accidents which happened on a Sunday: 693847
Accidents which happened on a Sunday involving > 20 cars: 10
Accidents which happened on a Sunday involving > 20 cars in the rain: 4
我们可以根据需要使场景越来越复杂。但是现在,我们将停下来。因为我们的主要兴趣是看发生在伦敦的事故。
如果你再看一下Road-Accident-Safety-Data-Guide-1979-2004.xls文件,有一个叫Police Force的表。 代号1的意思为“警视厅”,这就是通常被称为苏格兰警署,也就负责伦敦大部分(但不是全部)的警察部队。 对于我们而言,这已足够用,我们可以提取像这样这个信息:
# Accidents in London on a Sunday
london_data = data[data['Police_Force'] == 1 & (data.Day_of_Week == 1)]
print("\nAccidents in London from 1979-2004 on a Sunday: {0}".format(
len(london_data)))
运行该脚本,将创建了一个新的DataFrame表数据,包含着从1979至2004年星期天发生在“警视厅”的事故:
Accidents
-----------
Accidents which happened on a Sunday: 693847
Accidents which happened on a Sunday involving > 20 cars: 10
Accidents which happened on a Sunday involving > 20 cars in the rain: 4
Accidents in London from 1979-2004 on a Sunday: 114624
如果你想创建一个新的仅包含意外事故在2000年DataFrame表呢?
首先,我们需要通过pd.to_datetime() 函数,将日期格式转换为Python可以理解的格式。 这个函数可以将一个任何格式的日期数据,转换为使我们可以理解(YYYY-MM-DD)的格式。 然后,我们可以创建另一个仅包含2000年意外事故的DataFrame表:
# Convert date to Pandas date/time
london_data_2000 = london_data[
(pd.to_datetime(london_data['Date'], coerce=True) >
pd.to_datetime('2000-01-01', coerce=True)) &
(pd.to_datetime(london_data['Date'], coerce=True) <
pd.to_datetime('2000-12-31', coerce=True))
]
print("Accidents in London in the year 2000 on a Sunday: {0}".format(
len(london_data_2000)))
脚本执行后,你应该会看到:
Accidents which happened on a Sunday: 693847
Accidents which happened on a Sunday involving > 20 cars: 10
Accidents which happened on a Sunday involving > 20 cars in the rain: 4
Accidents in London from 1979-2004 on a Sunday: 114624
Accidents in London in the year 2000 on a Sunday: 3889
貌似这个结果有点混乱。通常情况下,如果要过滤一个数组数据,你只需要使用有限定条件for循环:
for data in array:
if data > X and data < X:
# do something
但是,你真的不应该定义自己的循环,因为许多高性能的库,例如Pandas,有对应的辅助函数。在这种情况下,上述代码遍历所有元件并过滤出的在数据集日期外的数据,然后,返回包含在日期范围内的数据。
干的不错!
转换数据
当公司的其他小伙伴深陷Excel无法自拔时,是不是有这样的机会,可以通过使用Pandas,将你生成的DataFrame表分享他们?
首先,我们需要做一些清理工作。还记得我们前面看到的字节顺序标记? 当写这个数据到Excel文件时会产生问题-Pandas会抛出一个UnicodeDecodeError错误。为什么呢? 因为文本的其余部分被解码为ASCII,但是十六进制值不能以ASCII表示。
我们可以将的一切编码为Unicode后写入,但要记住这个字节顺序标记是不必要的(对我们来说)。因此,我们通过重命名列标题来摆脱它:
london_data_2000.rename(
columns={'\xef\xbb\xbfAccident_Index': 'Accident_Index'}, inplace=True)
这是通过Pandas进行重命名列的方式; 有点复杂,但是说实话, inplace = True是需要的,因为我们要修改现有的结构,并且不创建副本,这是Pandas的默认操作。
现在,我们可以将数据保存到Excel:
# Save to Excel
writer = pd.ExcelWriter(
'London_Sundays_2000.xlsx', engine='xlsxwriter')
london_data_2000.to_excel(writer, 'Sheet1')
writer.save()
请确保安装XlsxWriter运行前:
pip install XlsxWriter==0.7.3
如果一切顺利,这应该已经创建了一个名为London_Sundays_2000.xlsx文件,然后保存我们的数据到工作表Sheet1。 打开此文件在Excel或LibreOffice中,并确认数据是正确的。
结论
那么,我们完成了哪些任务呢? 我们通过Pandas处理了在Excel中无法打开大的文件─
1. 打开该文件。
2. 执行类SQL的查询方式来处理数据。
3. 创建了由原始数据的解析的子集数据的新XLSX文件。
请记住,即使该文件是近800MB,在大数据时代,它仍然是相当小的。 如果你想打开一个4GB的文件? 即使你有8GB或更多的RAM,这可能仍然是不可能完成的。因为很多你的内存是被操作系统保和其他系统进程保留的。 事实上,当我首次读取800MB的文件时,我的笔记本电脑卡了几次。如果我打开一个4GB的文件,那对我的的笔记本电脑来说,不亚于一次心脏病发作。
那么我们该如何处理呢?
诀窍是不要一次性打的打开整个文件。这就是我们在接下来的博客文章需要了解的事情。
在此之前,分析自己的数据。
英文原文: https://realpython.com/blog/python/working-with-large-excel-files-in-pandas/
译者: LeoSun
'Python' 카테고리의 다른 글
python: 지정좌표 클릭, 드래그 (0) | 2021.02.28 |
---|---|
python:Python利用pandas处理Excel数据 (0) | 2021.02.08 |
python:정규표현식 ,정규표, 메타문자 (0) | 2020.09.10 |
001,직사각형을 만드는 데 필요한 4개의 점 중 3개의 좌표가 주어질 때, (0) | 2020.09.07 |
파이썬, pandas 사용법 001 (0) | 2020.09.01 |