Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将Excel文件读取到dataframe的更快方法_Python_Pandas_Import From Excel - Fatal编程技术网

Python 将Excel文件读取到dataframe的更快方法

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,

我有一个我正在读入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,
                       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的答案。Pandas
read_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&#252;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”中