Python 将Excel文件读取到dataframe的更快方法
我有一个我正在读入Pandas数据帧的代码,虽然下面的代码可以工作,但它需要9分钟 有人有加快速度的建议吗Python 将Excel文件读取到dataframe的更快方法,python,pandas,import-from-excel,Python,Pandas,Import From Excel,我有一个我正在读入Pandas数据帧的代码,虽然下面的代码可以工作,但它需要9分钟 有人有加快速度的建议吗 import pandas as pd def OTT_read(xl,site_name): df = pd.read_excel(xl.io,site_name,skiprows=2,parse_dates=0,index_col=0, usecols=[0,1,2],header=None,
import pandas as pd
def OTT_read(xl,site_name):
df = pd.read_excel(xl.io,site_name,skiprows=2,parse_dates=0,index_col=0,
usecols=[0,1,2],header=None,
names=['date_time','%s_depth'%site_name,'%s_temp'%site_name])
return df
def make_OTT_df(FILEDIR,OTT_FILE):
xl = pd.ExcelFile(FILEDIR + OTT_FILE)
site_names = xl.sheet_names
df_list = [OTT_read(xl,site_name) for site_name in site_names]
return site_names,df_list
FILEDIR='c:/downloads/'
OTT_FILE='OTT_Data_All_stations.xlsx'
site_names_OTT,df_list_OTT = make_OTT_df(FILEDIR,OTT_FILE)
正如其他人所建议的,csv读取速度更快。因此,如果您在windows上使用Excel,则可以调用vbscript将Excel转换为csv,然后读取csv。我尝试了下面的脚本,大约花了30秒
# create a list with sheet numbers you want to process
sheets = map(str,range(1,6))
# convert each sheet to csv and then read it using read_csv
df={}
from subprocess import call
excel='C:\\Users\\rsignell\\OTT_Data_All_stations.xlsx'
for sheet in sheets:
csv = 'C:\\Users\\rsignell\\test' + sheet + '.csv'
call(['cscript.exe', 'C:\\Users\\rsignell\\ExcelToCsv.vbs', excel, csv, sheet])
df[sheet]=pd.read_csv(csv)
下面是创建ExcelToCsv.vbs脚本的一小段python:
#write vbscript to file
vbscript="""if WScript.Arguments.Count < 3 Then
WScript.Echo "Please specify the source and the destination files. Usage: ExcelToCsv <xls/xlsx source file> <csv destination file> <worksheet number (starts at 1)>"
Wscript.Quit
End If
csv_format = 6
Set objFSO = CreateObject("Scripting.FileSystemObject")
src_file = objFSO.GetAbsolutePathName(Wscript.Arguments.Item(0))
dest_file = objFSO.GetAbsolutePathName(WScript.Arguments.Item(1))
worksheet_number = CInt(WScript.Arguments.Item(2))
Dim oExcel
Set oExcel = CreateObject("Excel.Application")
Dim oBook
Set oBook = oExcel.Workbooks.Open(src_file)
oBook.Worksheets(worksheet_number).Activate
oBook.SaveAs dest_file, csv_format
oBook.Close False
oExcel.Quit
""";
f = open('ExcelToCsv.vbs','w')
f.write(vbscript.encode('utf-8'))
f.close()
#将vbscript写入文件
vbscript=“”如果WScript.Arguments.Count<3,则
Echo“请指定源文件和目标文件。用法:ExcelToCsv“
Wscript.Quit
如果结束
csv_格式=6
设置objFSO=CreateObject(“Scripting.FileSystemObject”)
src_file=objFSO.GetAbsolutePathName(Wscript.Arguments.Item(0))
dest_file=objFSO.GetAbsolutePathName(WScript.Arguments.Item(1))
工作表_number=CInt(WScript.Arguments.Item(2))
暗色oExcel
设置oExcel=CreateObject(“Excel.Application”)
Dim oBook
设置oBook=oExcel.Workbooks.Open(src_文件)
oBook.工作表(工作表编号)。激活
oBook.SaveAs dest_文件,csv_格式
好的,关上
oExcel,退出
""";
f=打开('ExcelToCsv.vbs','w')
f、 写入(vbscript.encode('utf-8'))
f、 关闭()
这个答案得益于
xlsx
,并且如果你的行数少于65536行(每页),你可以尝试xls
(而不是xlsx
。根据我的经验xls
比xlsx
快。很难与csv
进行比较,因为它取决于页数
虽然这不是一个理想的解决方案(
xls
是一种二进制旧私有格式),我发现,如果您使用的是大量工作表,内部公式的值经常更新,或者出于任何原因,您希望保留excel多页功能(而不是csv分隔的文件),则此功能非常有用.我知道这很旧,但如果其他人正在寻找一个不涉及VB的答案。Pandasread_csv()
速度更快,但您不需要VB脚本来获取csv文件
打开Excel文件并另存为*.csv(逗号分隔值)格式
在“工具”下,您可以选择Web选项,在“编码”选项卡下,您可以将编码更改为对数据有效的任何编码。我最终使用了西欧Windows,因为Windows UTF编码是“特殊”的,但有很多方法可以实现这一点。然后使用pd.read\u csv()中的编码参数
指定您的编码
编码选项已列出如果您愿意处理一次缓慢的转换,则没有理由打开excel
pd.Read\u excel()
pd.to\u csv()
避免excel和windows特定的调用。在我的情况下,一次性命中是值得的。我得到了一个☕. 根据我的经验,Pandas
read\u excel()
可以很好地处理包含多个工作表的excel文件。如中所建议的,如果将sheet\u name
指定给None
它将自动将每个工作表放入数据框中,并输出带有工作表名称键的数据框字典
但这需要时间的原因是,您需要在代码中解析文本。14MB excel,包含5张工作表并不多。我有一个20.1MB excel文件,其中46张工作表,每一张工作表超过6000行和17列,使用read_excel
,结果如下:
t0 = time.time()
def parse(datestr):
y,m,d = datestr.split("/")
return dt.date(int(y),int(m),int(d))
data = pd.read_excel("DATA (1).xlsx", sheet_name=None, encoding="utf-8", skiprows=1, header=0, parse_dates=[1], date_parser=parse)
t1 = time.time()
print(t1 - t0)
## result: 37.54169297218323 seconds
在上面的代码中,数据是46个数据帧的字典
如其他建议的那样,使用<代码> Read Oracle()>代码>可以帮助,因为读取<代码> .CSV 文件更快。但是考虑到“代码> .xLSX < /Cord>文件使用压缩,<代码> .CSV 文件可能较大,因此读取速度较慢。但是如果您想用Python将文件转换为逗号分隔的话(VBcode由提供),您可以使用:
我编写了一个快速脏脚本,只从.xlsx文件中读取值。这不会更新值(如日期),只适用于我使用的文件。可能仍然存在一些错误,因为我只是在没有仔细研究xlsx定义的情况下写下了它:-).但是它比默认的pd.read\u excel快五到十倍# -*- coding: utf-8 -*-
"""
Created on Fri Jan 3 16:42:08 2020
@author: FelixKling
"""
import re
import zipfile
import pandas as pd
import datetime as dt
import numpy as np
import html
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
def read(path, sheet_name=None, header=True, index_col=False, skiprows=[], skipcolumns=[]):
"""
Reads an .xlsx or .xlsm file and returns a Pandas DataFrame. Is much faster than pandas.read_excel().
Parameters
----------
path : str
The path to the .xlsx or .xlsm file.
sheet_name : str, optional
Name of the sheet to read. If none, the first (not the active!) sheet is read. The default is None.
header : bool, optional
Whether to use the first line as column headers. The default is True.
index_col : bool, optional
Whether to use the first column as index. The default is False.
skiprows : list of int, optional.
The row numbers to skip ([0, 1] skips the first two rows). The default is [].
skipcolumns : list of int, optional.
The column numbers to skip ([0, 1] skips the first two columns). The default is [].
Raises
------
TypeError
If the file is no .xlsx or .xlsm file.
FileNotFoundError
If the sheet name is not found.
Returns
-------
Pandas DataFrame
The input file as DataFrame.
"""
# check extension
if "." not in path:
raise TypeError("This is no .xlsx or .xlsm file!")
if path.rsplit(".", 1)[1] not in ["xlsx", "xlsm"]:
raise TypeError("This is no .xlsx or .xlsm file!")
path = path.replace("\\","/")
tempfiles = dict()
with zipfile.ZipFile(path, 'r') as zipObj:
for name in zipObj.namelist():
if name.startswith("xl/worksheets/") or name in [
"xl/_rels/workbook.xml.rels",
"xl/styles.xml",
"xl/workbook.xml",
"xl/sharedStrings.xml",
]:
try:
tempfiles[name] = zipObj.read(name).decode("utf-8")
except UnicodeDecodeError:
tempfiles[name] = zipObj.read(name).decode("utf-16")
# read rels (paths to sheets)
text = tempfiles["xl/_rels/workbook.xml.rels"]
rels = {}
relids = re.findall(r'<Relationship Id="([^"]+)"', text)
relpaths = re.findall(r'<Relationship .*?Target="([^"]+)"', text)
rels = dict(zip(relids, relpaths))
# read sheet names and relation ids
if sheet_name:
text = tempfiles["xl/workbook.xml"]
workbooks = {}
workbookids = re.findall(r'<sheet.*? r:id="([^"]+)"', text)
workbooknames = re.findall(r'<sheet.*? name="([^"]+)"', text)
workbooks = dict(zip(workbooknames, workbookids))
if sheet_name in workbooks:
sheet = rels[workbooks[sheet_name]].rsplit("/", 1)[1]
else:
raise FileNotFoundError("Sheet " + str(sheet_name) + " not found in Excel file! Available sheets: " + "; ".join(workbooks.keys()))
else:
sheet="sheet1.xml"
# read strings, they are numbered
string_items = []
if "xl/sharedStrings.xml" in tempfiles:
text = tempfiles["xl/sharedStrings.xml"]
string_items = re.split(r"<si.*?><t.*?>", text.replace("<t/>", "<t></t>").replace("</t></si>","").replace("</sst>",""))[1:]
string_items = [html.unescape(str(i).split("</t>")[0]) if i != "" else np.nan for i in string_items]
# read styles, they are numbered
text = tempfiles["xl/styles.xml"]
styles = re.split(r"<[/]?cellXfs.*?>", text)[1]
styles = styles.split('numFmtId="')[1:]
styles = [int(s.split('"', 1)[0]) for s in styles]
numfmts = text.split("<numFmt ")[1:]
numfmts = [n.split("/>", 1)[0] for n in numfmts]
for i, n in enumerate(numfmts):
n = re.sub(r"\[[^\]]*\]", "", n)
n = re.sub(r'"[^"]*"', "", n)
if any([x in n for x in ["y", "d", "w", "q"]]):
numfmts[i] = "date"
elif any([x in n for x in ["h", "s", "A", "P"]]):
numfmts[i] = "time"
else:
numfmts[i] = "number"
def style_type(x):
if 14 <= x <= 22:
return "date"
if 45 <= x <= 47:
return "time"
if x >= 165:
return numfmts[x - 165]
else:
return "number"
styles = list(map(style_type, styles))
text = tempfiles["xl/worksheets/" + sheet]
def code2nr(x):
nr = 0
d = 1
for c in x[::-1]:
nr += (ord(c)-64) * d
d *= 26
return nr - 1
table = []
max_row_len = 0
rows = [r.replace("</row>", "") for r in re.split(r"<row .*?>", text)[1:]]
for r in rows:
# c><c r="AT2" s="1" t="n"><v></v></c><c r="AU2" s="115" t="inlineStr"><is><t>bla (Namenskürzel)</t></is></c>
r = re.sub(r"</?r.*?>","", r)
r = re.sub(r"<(is|si).*?><t.*?>", "<v>", r)
r = re.sub(r"</t></(is|si)>", "</v>", r)
r = re.sub(r"</t><t.*?>","", r)
values = r.split("</v>")[:-1]
add = []
colnr = 0
for v in values:
value = re.split("<v.*?>", v)[1]
v = v.rsplit("<c", 1)[1]
# get column number of the field
nr = v.split(' r="')[1].split('"')[0]
nr = code2nr("".join([n for n in nr if n.isalpha()]))
if nr > colnr:
for i in range(nr - colnr):
add.append(np.nan)
colnr = nr + 1
sty = "number"
if ' s="' in v:
sty = int(v.split(' s="', 1)[1].split('"', 1)[0])
sty = styles[sty]
# inline strings
if 't="inlineStr"' in v:
add.append(html.unescape(value) if value != "" else np.nan)
# string from list
elif 't="s"' in v:
add.append(string_items[int(value)])
# boolean
elif 't="b"' in v:
add.append(bool(int(value)))
# date
elif sty == "date":
if len(value) == 0:
add.append(pd.NaT)
# Texts like errors
elif not is_number(value):
add.append(html.unescape(value))
else:
add.append(dt.datetime(1900,1,1) + dt.timedelta(days=float(value) - 2))
# time
elif sty == "time":
if len(value) == 0:
add.append(pd.NaT)
# Texts like errors
elif not is_number(value):
add.append(html.unescape(value))
else:
add.append((dt.datetime(1900,1,1) + dt.timedelta(days=float(value) - 2)).time())
# Null
elif len(value) == 0:
add.append(np.nan)
# Texts like errors
elif not is_number(value):
add.append(html.unescape(value))
# numbers
else:
add.append(round(float(value), 16))
table.append(add)
if len(add) > max_row_len:
max_row_len = len(add)
df = pd.DataFrame(table)
# skip rows or columns
df = df.iloc[[i for i in range(len(df)) if i not in skiprows], [i for i in range(len(df.columns)) if i not in skipcolumns]]
if index_col:
df = df.set_index(df.columns[0])
if header:
df.columns = df.iloc[0].values
df = df.iloc[1:]
return df
#-*-编码:utf-8-*-
"""
创建于2020年1月3日星期五16:42:08
@作者:FelixKling
"""
进口稀土
进口拉链
作为pd进口熊猫
将日期时间导入为dt
将numpy作为np导入
导入html
def是_编号:
尝试:
浮球
返回真值
除值错误外:
返回错误
def read(路径,工作表名称=无,标题=真,索引列=假,skiprows=[],skipcolumns=[]):
"""
读取.xlsx或.xlsm文件并返回Pandas数据帧。比Pandas.read\u excel()快得多。
参数
----------
路径:str
.xlsx或.xlsm文件的路径。
图纸名称:str,可选
要读取的工作表的名称。如果无,则读取第一个(非活动!)工作表。默认值为无。
标题:bool,可选
是否将第一行用作列标题。默认值为True。
索引列:布尔,可选
是否将第一列用作索引。默认值为False。
skiprows:整数列表,可选。
要跳过的行号([0,1]跳过前两行)。默认值为[]。
skipcolumns:int列表,可选。
要跳过的列号([0,1]跳过前两列)。默认值为[]。
提高
------
打字错误
如果文件不是.xlsx或.xlsm文件。
FileNotFoundError
如果找不到图纸名称。
退换商品
-------
熊猫数据帧
将输入文件设置为DataFrame。
"""
#检查分机
如果“.”不在路径中:
raise TypeError(“这不是.xlsx或.xlsm文件!”)
如果path.rsplit(“.”,1)[1]不在[“xl”中