Pandy: przeglądanie listy arkuszy w pliku Excel

142

Nowa wersja Pandas używa następującego interfejsu do ładowania plików Excel:

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

ale co, jeśli nie znam dostępnych arkuszy?

Na przykład pracuję z plikami programu Excel, które znajdują się poniżej

Dane 1, Dane 2 ..., Dane N, foo, bar

ale nie wiem Na priori.

Czy jest jakiś sposób, aby uzyskać listę arkuszy z dokumentu Excela w Pandach?

Amelio Vazquez-Reina
źródło

Odpowiedzi:

251

Nadal możesz używać klasy ExcelFile (i sheet_namesatrybutu):

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

xl.sheet_names  # see all sheet names

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

zobacz dokumentację do analizy, aby uzyskać więcej opcji ...

Andy Hayden
źródło
1
Dzięki @ Andy. Mogę zapytać, czy Pandy ładują arkusz Excela ExcelFile? Powiedzmy również, że przeglądam listę arkuszy i decyduję się załadować N z nich. Czy powinienem w tym momencie wywołać read_excel(nowy interfejs) dla każdego arkusza, czy trzymać się x1.parse?
Amelio Vazquez-Reina
2
Myślę, że ExcelFile utrzymuje plik otwarty (i nie czyta go w całości), myślę, że użycie parsowania (i otwarcie pliku tylko raz) ma tutaj największy sens. tbh przegapiłem przybycie read_excel!
Andy Hayden
6
Wspomniano wcześniej tutaj , ale lubię prowadzić słownik DataFrames przy użyciu{sheet_name: xl.parse(sheet_name) for sheet_name in xl.sheet_names}
Andy Hayden
2
Szkoda, że ​​nie mogę dać Ci więcej głosów za, to działa również w wielu wersjach pand! (nie wiem, dlaczego tak często lubią zmieniać API) Dziękuję za wskazanie mi funkcji parsowania, ale tutaj jest obecny link: pandas.pydata.org/pandas-docs/stable/generated/ ...
Ezekiel Kruglick
3
@NicholasLu głos przeciw nie jest konieczny, ta odpowiedź pochodzi z 2013 roku! To powiedziawszy, chociaż ExcelFile jest oryginalnym sposobem analizowania plików Excela, nie jest on przestarzały i pozostaje całkowicie prawidłowym sposobem na zrobienie tego.
Andy Hayden
36

Należy jawnie określić drugi parametr (nazwa arkusza) jako Brak. lubię to:

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

„df” to wszystkie arkusze jako słownik DataFrames, możesz to sprawdzić, uruchamiając to:

df.keys()

wynik taki jak ten:

[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']

więcej szczegółów można znaleźć w dokumencie pandas: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html

Nicholas Lu
źródło
3
To niepotrzebnie analizuje każdy arkusz jako DataFrame, co nie jest wymagane. „Jak czytać plik xls / xlsx” to inne pytanie .
Andy Hayden
7
@AndyHayden to może nie być wydajne, ale może być najlepsze, jeśli zależy Ci na wszystkich arkuszach lub nie przejmujesz się dodatkowymi kosztami.
CodeMonkey,
8

To najszybszy sposób, jaki znalazłem, zainspirowany odpowiedzią @ivingTobi. Wszystkie Odpowiedzi oparte na xlrd, openpyxl lub pandach są dla mnie powolne, ponieważ wszystkie ładują najpierw cały plik.

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")]
MORZE
źródło
3

Opierając się na odpowiedzi @dhwanil_shah, nie musisz rozpakowywać całego pliku. Dzięki zf.opentemu możliwe jest bezpośrednie odczytanie z pliku spakowanego.

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

Dwa kolejne readlines są brzydkie, ale treść znajduje się tylko w drugim wierszu tekstu. Nie ma potrzeby analizowania całego pliku.

To rozwiązanie wydaje się być znacznie szybsze niż read_excelwersja, a najprawdopodobniej także szybsze niż pełna wersja wypakowania.

nurkowanieTobi
źródło
Nie, .xls to zupełnie inny format pliku, więc nie spodziewałbym się, że ten kod będzie działał.
nurkowanieTobi
2

Wypróbowałem xlrd, pandas, openpyxl i inne tego typu biblioteki i wszystkie z nich wydają się zajmować wykładniczy czas, ponieważ rozmiar pliku rośnie, gdy odczytuje cały plik. Inne wymienione powyżej rozwiązania, w których używali „on_demand”, nie działały u mnie. Jeśli chcesz tylko początkowo uzyskać nazwy arkuszy, następująca funkcja działa dla plików xlsx.

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

Ponieważ wszystkie xlsx są w zasadzie spakowanymi plikami, wyodrębniamy podstawowe dane xml i czytamy nazwy arkuszy bezpośrednio ze skoroszytu, co zajmuje ułamek sekundy w porównaniu z funkcjami biblioteki.

Benchmarking: (na pliku 6mb xlsx z 4 arkuszami)
Pandy, xlrd: 12 sekund
openpyxl: 24 sekundy
Proponowana metoda: 0,4 sekundy

Ponieważ moim wymaganiem było po prostu czytanie nazw arkuszy, niepotrzebne obciążenie związane z czytaniem przez cały czas mnie niepokoiło, więc zamiast tego wybrałem tę trasę.

Dhwanil shah
źródło
Z jakich modułów korzystasz?
Daniel
@Daniel Użyłem tylko tego, zipfilektóry jest wbudowanym modułem i xmltodictktórego użyłem do konwersji XML na łatwo iterowalny słownik. Chociaż możesz spojrzeć na odpowiedź @ivingTobi poniżej, gdzie możesz odczytać ten sam plik bez faktycznego wyodrębniania plików w nim zawartych.
Dhwanil shah
Kiedy próbowałem openpyxl z flagą read_only, jest to znacznie szybsze (200X szybsze dla mojego pliku 5 MB). load_workbook(excel_file).sheetnamesśrednio 8,24s, gdzie load_workbook(excel_file, read_only=True).sheetnamesśrednio 39,6ms.
flutefreak7
0
from openpyxl import load_workbook

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

Dla 5MB pliku Excel, z którym pracuję, load_workbookbez read_onlyflagi zajęło 8,24s. Z read_onlyflagą zajęło to tylko 39,6 ms. Jeśli nadal chcesz korzystać z biblioteki programu Excel i nie upuszczać go do rozwiązania XML, jest to znacznie szybsze niż metody analizujące cały plik.

flutefreak7
źródło