Pandas: Nachschlagen der Liste der Blätter in einer Excel-Datei

141

Die neue Version von Pandas verwendet die folgende Oberfläche zum Laden von Excel-Dateien:

read_excel('path_to_file.xls', 'Sheet1', index_col=None, na_values=['NA'])

aber was ist, wenn ich die verfügbaren Blätter nicht kenne?

Zum Beispiel arbeite ich mit Excel-Dateien, die die folgenden Blätter

Daten 1, Daten 2 ..., Daten N, foo, bar

aber ich weiß nicht Na priori.

Gibt es eine Möglichkeit, die Liste der Blätter aus einem Excel-Dokument in Pandas abzurufen?

Amelio Vazquez-Reina
quelle

Antworten:

250

Sie können weiterhin die ExcelFile- Klasse (und das sheet_namesAttribut) verwenden:

xl = pd.ExcelFile('foo.xls')

xl.sheet_names  # see all sheet names

xl.parse(sheet_name)  # read a specific sheet to DataFrame

Weitere Optionen finden Sie in den Dokumenten zum Analysieren ...

Andy Hayden
quelle
1
Danke @Andy. Darf ich fragen, lädt Pandas das Excel-Blatt ein ExcelFile? Angenommen, ich schaue in der Liste der Blätter nach und entscheide mich, N davon zu laden. Soll ich an diesem Punkt read_excel(die neue Schnittstelle) für jedes Blatt aufrufen oder mich daran halten x1.parse?
Amelio Vazquez-Reina
2
Ich denke, ExcelFile hält die Datei offen (und liest nicht alles). Ich denke, die Verwendung von parse (und das Öffnen der Datei nur einmal) ist hier am sinnvollsten. tbh Ich habe die Ankunft von read_excel verpasst!
Andy Hayden
6
Erwähnt vor hier , aber Ich mag ein Wörterbuch von Datenrahmen halten mit{sheet_name: xl.parse(sheet_name) for sheet_name in xl.sheet_names}
Andy Hayden
2
Ich wünschte, ich könnte Ihnen mehr Upvotes geben, dies funktioniert auch in mehreren Versionen von Pandas! (Ich weiß nicht, warum sie die API so oft ändern.) Vielen Dank, dass Sie mich auf die Analysefunktion
hingewiesen haben.
3
@NicholasLu die Abwertung war unnötig, diese Antwort ist von 2013! Obwohl ExcelFile die ursprüngliche Methode zum Parsen von Excel-Dateien ist, ist es nicht veraltet und bleibt eine absolut gültige Methode, dies zu tun.
Andy Hayden
37

Sie sollten den zweiten Parameter (Blattname) explizit als Keine angeben. so was:

 df = pandas.read_excel("/yourPath/FileName.xlsx", None);

"df" sind alle Blätter als Wörterbuch von DataFrames. Sie können dies überprüfen, indem Sie Folgendes ausführen:

df.keys()

Ergebnis wie folgt:

[u'201610', u'201601', u'201701', u'201702', u'201703', u'201704', u'201705', u'201706', u'201612', u'fund', u'201603', u'201602', u'201605', u'201607', u'201606', u'201608', u'201512', u'201611', u'201604']

Weitere Informationen finden Sie im Pandas-Dokument: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html

Nicholas Lu
quelle
3
Dadurch wird unnötigerweise jedes Blatt als DataFrame analysiert, was nicht erforderlich ist. "Wie man eine xls / xlsx-Datei liest" ist eine andere Frage .
Andy Hayden
7
@AndyHayden Es ist möglicherweise nicht effizient, aber es ist möglicherweise das Beste, wenn Sie sich um alle Blätter kümmern oder sich nicht um den zusätzlichen Aufwand kümmern.
CodeMonkey
8

Dies ist der schnellste Weg, den ich gefunden habe, inspiriert von der Antwort von @ divingTobi. Alle Die Antworten basierend auf xlrd, openpyxl oder pandas sind für mich langsam, da alle zuerst die gesamte Datei laden.

from zipfile import ZipFile
from bs4 import BeautifulSoup  # you also need to install "lxml" for the XML parser

with ZipFile(file) as zipped_file:
    summary = zipped_file.open(r'xl/workbook.xml').read()
soup = BeautifulSoup(summary, "xml")
sheets = [sheet.get("name") for sheet in soup.find_all("sheet")]
MEER
quelle
3

Aufbauend auf der Antwort von @dhwanil_shah müssen Sie nicht die gesamte Datei extrahieren. Mit ist zf.openes möglich, direkt aus einer komprimierten Datei zu lesen.

import xml.etree.ElementTree as ET
import zipfile

def xlsxSheets(f):
    zf = zipfile.ZipFile(f)

    f = zf.open(r'xl/workbook.xml')

    l = f.readline()
    l = f.readline()
    root = ET.fromstring(l)
    sheets=[]
    for c in root.findall('{http://schemas.openxmlformats.org/spreadsheetml/2006/main}sheets/*'):
        sheets.append(c.attrib['name'])
    return sheets

Die zwei aufeinanderfolgenden readline s sind hässlich, aber der Inhalt befindet sich nur in der zweiten Zeile des Textes. Sie müssen nicht die gesamte Datei analysieren.

Diese Lösung scheint viel schneller als die read_excelVersion zu sein und höchstwahrscheinlich auch schneller als die vollständige Extraktversion.

TauchenTobi
quelle
Nein, .xls ist ein völlig anderes Dateiformat, daher würde ich nicht erwarten, dass dieser Code funktioniert.
TauchenTobi
2

Ich habe xlrd, pandas, openpyxl und andere solche Bibliotheken ausprobiert und alle scheinen exponentielle Zeit in Anspruch zu nehmen, wenn die Dateigröße zunimmt, während die gesamte Datei gelesen wird. Die anderen oben genannten Lösungen, bei denen 'on_demand' verwendet wurde, funktionierten bei mir nicht. Wenn Sie zunächst nur die Blattnamen abrufen möchten, funktioniert die folgende Funktion für XLSX-Dateien.

def get_sheet_details(file_path):
    sheets = []
    file_name = os.path.splitext(os.path.split(file_path)[-1])[0]
    # Make a temporary directory with the file name
    directory_to_extract_to = os.path.join(settings.MEDIA_ROOT, file_name)
    os.mkdir(directory_to_extract_to)

    # Extract the xlsx file as it is just a zip file
    zip_ref = zipfile.ZipFile(file_path, 'r')
    zip_ref.extractall(directory_to_extract_to)
    zip_ref.close()

    # Open the workbook.xml which is very light and only has meta data, get sheets from it
    path_to_workbook = os.path.join(directory_to_extract_to, 'xl', 'workbook.xml')
    with open(path_to_workbook, 'r') as f:
        xml = f.read()
        dictionary = xmltodict.parse(xml)
        for sheet in dictionary['workbook']['sheets']['sheet']:
            sheet_details = {
                'id': sheet['@sheetId'],
                'name': sheet['@name']
            }
            sheets.append(sheet_details)

    # Delete the extracted files directory
    shutil.rmtree(directory_to_extract_to)
    return sheets

Da es sich bei allen xlsx im Grunde genommen um komprimierte Dateien handelt, extrahieren wir die zugrunde liegenden XML-Daten und lesen die Blattnamen direkt aus der Arbeitsmappe, was im Vergleich zu den Bibliotheksfunktionen einen Bruchteil einer Sekunde dauert.

Benchmarking: (Auf einer 6-MB-xlsx-Datei mit 4 Blättern)
Pandas, xlrd: 12 Sekunden
openpyxl: 24 Sekunden
Vorgeschlagene Methode: 0,4 Sekunden

Da ich nur die Blattnamen lesen musste, nervte mich der unnötige Aufwand beim Lesen der gesamten Zeit, sodass ich stattdessen diesen Weg einschlug.

Dhwanil shah
quelle
Welche Module verwenden Sie?
Daniel
@ Daniel Ich habe nur zipfileein eingebautes Modul verwendet, mit xmltodictdem ich das XML in ein leicht iterierbares Wörterbuch konvertiert habe. Sie können sich jedoch die Antwort von @ divingTobi unten ansehen, in der Sie dieselbe Datei lesen können, ohne die darin enthaltenen Dateien tatsächlich zu extrahieren.
Dhwanil shah
Als ich openpyxl mit dem read_only-Flag ausprobiert habe, ist es deutlich schneller (200-mal schneller für meine 5-MB-Datei). load_workbook(excel_file).sheetnamesdurchschnittlich 8,24 s, wo load_workbook(excel_file, read_only=True).sheetnamesdurchschnittlich 39,6 ms.
Flutefreak7
0
from openpyxl import load_workbook

sheets = load_workbook(excel_file, read_only=True).sheetnames

Für eine 5-MB-Excel-Datei, mit der ich arbeite, dauerte load_workbookdas read_onlyFlag 8,24 Sekunden. Mit der read_onlyFlagge dauerte es nur 39,6 ms. Wenn Sie weiterhin eine Excel-Bibliothek verwenden und nicht zu einer XML-Lösung wechseln möchten, ist dies viel schneller als die Methoden, mit denen die gesamte Datei analysiert wird.

Flötenbruch7
quelle