Help us understand the problem. What is going on with this article?

ExcelのデータをPython、C#で読み込むまとめ

More than 1 year has passed since last update.

Webアプリ用のデータをExcelを使って作っている関係で、Python、C#でExcelファイルを読み込むためのライブラリーを比較してみました。(.NET Core 2.1、Python3.7 が公開されたので記載内容を修正 2018年7月3日)

Excelファイルを読み込むための方法として、Microsoft.Office.Interop.Excelを使ったCOM参照による方法を紹介している記事も多いですが、それを使うのは処理が遅いし、問題も多いし、そもそも Excel が必要なので Linux サーバーだと動作しません。以下に紹介する OSS のライブラリーはかなり改善されていて、少し注意すれば問題なくかつ高速に処理することができます。

パフォーマンス比較

Excelのファイルを読み込みTSV形式で出力するコンソールアプリケーションを作成し、それの起動から終了までの時間を測定しました。Excelのファイルは、589行☓235列の表でxlsx形式で829KBのものを使いました。

テストに使ったソースコード及びデータは、GitHubの方に公開してあります。まだ、整理はできていませんが興味があればみてください。

テスト結果

Linux(Ubuntu 18.04)

ライブラリ バージョン xlsx 読込処理時間 xls 読込処理時間
Pandas (xlrd) 0.23.1 (1.1.0) 898 572
openpyxl 2.5.4 1314 -
ExcelDataReader 3.4.0 704 341
DotNetCore.NPOI 1.0.2 1016 384
EPPlus 4.5.2.1 1954 -
ClosedXML 0.93.0 2336 -

処理時間は、ExcelDataReaderが最も速くなりました。一方、Pandasを使うと、ExcelDataReader を使うより読み込み時間は1.3〜1.6倍ぐらいかかりますが、プログラムは1行で書けるし、読み込んだ後のデータの加工のための機能が多くNumpyを使って高速な処理ができるので便利です。自分はPandasを使うことに決めました。

各ライブラリーの特徴

以下では、各ライブラリーの特徴と Excel の xlsx ファイルを読み込んで、tsv 形式で書き出すコードを載せています。

Python

Pandas (xlrd)

xlrd は、単独で Excelファイルを読み込むことができますが、pandas.read_excel を使って Pandas のデータフレームに変換した方が処理が楽です。以下のように簡単な記述で tsv 形式に変換できます。pandas.read_excel を使用する場合 xlrd の import 文を書く必要はありませんが、ライブラリーをインストールしておく必要はあります。

example.py
import pandas as pd

df = pd.read_excel(in_path, header=None)
df.to_csv(out_path, header=False, sep='\t', index=False)

データフレームには多くのAPIがあり、csv形式以外に、json, HTMLテーブル,SQLデータベース等に簡単に出力できます。

データフレームは、df.iat[0, 0]のようにしてCellの番号でCellの値を取得したり設定したりすることができるので、VBAやC#でよくするようにfor文で処理をすることもできますが、行列での演算が整備されているので、そちらの方を使うことが多くなります。

上の式では、任意の表を扱えるように header=None にしていますが、データベース形式のようにヘッダーがきちんとある場合は、例えば3行目にある場合はheader=2と指定するとヘッダーの名前で列を指定できるので便利です。

また、上の式のようにシート名を指定していない場合は、一番最初のシートが読み込まれます。シートを指定したい場合は、sheet_name='シート名'又は2番目のシートであればsheet_name=1のように番号で指定することができます。詳しくは、pandas.read_excelのマニュアルをみてください。

openpyxl

openpyxlは、Excel 2010 の xlsx/xlsm/xltx/xltmfor ファイルを読み書きできる Python のライブラリーです。PythonにはExcelファイルを操作するためのライブラリーがいくつかありますが、その中で最もよく使われるライブラリーの一つです。

example.py
from openpyxl import load_workbook
import csv

def iter_row(row):
    yield [cell.value for cell in row]

wb = load_workbook(in_path, read_only=True)
sheet = wb.worksheets[0]
with open(out_path, 'w') as f:
    writer = csv.writer(f, delimiter='\t', quoting=csv.QUOTE_MINIMAL)
    for row in sheet.rows:
        writer.writerows(iter_row(row))

Excelのセルには、上の場合であればsheet['A1']又はsheet.cell(row=1, column=1)のようにしてアクセスできます。

C#

ExcelDataReader

読み込み専用のソフトで、高速に処理できるのが特徴で、海外では以前から人気のあるライブラリーです。かっては日本語の処理に問題があったのですが、現時点では解消されたので、日本語でも安心して使えます。Excel 2.0 から Excel 2007以降のOpen XML形式まで広く対応しています。

example.cs
using (var stream = File.Open(inFile, FileMode.Open, FileAccess.Read))          
using (var excelReader = ExcelReaderFactory.CreateReader(stream))
{
    var result = excelReader.AsDataSet();
    var sb = new StringBuilder();

    foreach (DataRow datarow in result.Tables[0].Rows)
    {
        sb.Append(datarow.ItemArray.Aggregate((s, x) => s + "\t" + x.ToString()));
        sb.Append("\n");
    }
    File.WriteAllText(outFile, sb.ToString());
}

EPPlus

Office Open XML 形式(xlsx)の読み込み及び書き込みに対応しています。チャートや VBA を操作できる API もあり、Excel に関して言えば NPOI よりも機能は豊富です。.NET Core で使う場合は、Ver4.5からの対応なので現在は RC のものを使う必要があります。また、.NETStandard 2.0 の対応なので、.NET Core では 2.0 からの対応になります。

EPPlusでは、Cellsの番号は1から始まります。

example.cs
FileInfo newFile = new FileInfo(infile);
ExcelPackage pck = new ExcelPackage(newFile);
//Ver4.5では、Worksheetsは 0 から始まるように変更
ExcelWorksheet sheet = pck.Workbook.Worksheets[1];

var sb = new StringBuilder();
int rows = sheet.Dimension.Rows;

for (int r = 1; r <= rows; r++)
{
    for (int c = 1; c <= sheet.Dimension.Columns; c++)
        sb.Append(sheet.Cells[r, c].Text + "\t");

    sb.Remove(sb.Length - 1, 1);
    sb.Append("\n");         
}
File.WriteAllText(outFile, sb.ToString());

NPOI

Java の Apacche POI を .NET に移植したものです。2007 の xlsx 及び 2003 の xls ファイルの双方に対応しており、読み込みも書き出しもできます。Excel だけでなく docx にも対応しています。Tony Qu's NPOIは.NET Core には対応していませんが、それから派生した DotNetCore.NPOIが、.NET Standard 2.0 に対応しているので、.NET Core 2.0 でも動作します。DotNetCore.NPOI は ZKWeb.System.Drawing を使っているので Linux で動作させる場合には、libgdiplus が必要になります。

NPOIは、Cellsの番号は0からになります。

example.cs
FileStream stream = File.OpenRead(inFile);
var book = new XSSFWorkbook(stream);
stream.Close();
ISheet sheet = book.GetSheetAt(0);
int lastRowNum = sheet.LastRowNum;

var sb = new StringBuilder();
for (int r = 0; r < sheet.LastRowNum; r++)
{
    var datarow = sheet.GetRow(r);
    {
        foreach (ICell cell in datarow.Cells)
        { 
            if(cell.CellType == CellType.Numeric)
                sb.Append(cell.NumericCellValue + "\t");
            else
                sb.Append(cell.StringCellValue + "\t");
        }       
        sb.Remove(sb.Length - 1, 1);
        sb.Append("\n");
    }
}
File.WriteAllText(outFile, sb.ToString());

ClosedXML

Microsoft 純正の Open XML SDK をそのままで使うのはあまりにも面倒なので、それを使いやすくしたライブラリーです。ベースとしてOpen XML SDK を使うので、対応する Excel のファイル形式は、Excel2007以降のOpen XML形式のものになります。Open XML SDK がベースなので機能は豊富ですが、処理は少し重いです。

sheet.Cells()を使って処理をすると処理がものすごく遅くなるので、sheet.Rows()を使ってforeachで行ごとに処理をしています。

example.cs
var workbook = new ClosedXML.Excel.XLWorkbook(inFile);
ClosedXML.Excel.IXLWorksheet sheet = workbook.Worksheets.Worksheet(1);
var sb = new StringBuilder();
var rows = sheet.LastRowUsed().RangeAddress.FirstAddress.RowNumber;
var columns = sheet.LastColumnUsed().RangeAddress.FirstAddress.ColumnNumber;

foreach(var row in sheet.Rows())
{
    foreach (var cell in row.Cells())
        sb.Append(cell.GetString() + "\t");
    sb.Remove(sb.Length - 1, 1);
    sb.Append("\n");
}
File.WriteAllText(outFile, sb.ToString());

参考 Windows(Windows10)でのテスト結果

Windows(Windows10)でのテスト結果は以下のとおりでした。Windows と Linux は、同一のPCでデュアルブートで立ち上げたものを使っています。処理時間の単位はミリ秒です。

ライブラリ バージョン xlsx 読込処理時間 xls 読込処理時間
Pandas (xlrd) 0.23.1 (1.1.0) 1148 755
openpyxl 2.5.4 1848 -
ExcelDataReader(.NET Framework) 3.4.0 581 344
ExcelDataReader(.NET Core) 3.4.0 610 353
NPOI(.NET Framework) 2.3.0 1004 372
DotNetCore.NPOI(.NET Core) 1.0.2 1062 388
EPPlus(.NET Framework) 4.5.2.1 1310 -
EPPlus(.NET Core) 4.5.2.1 1246 -
ClosedXML(.NET Framework) 0.93.0 2202 -
ClosedXML(.NET Core) 0.93.0 2069 -

.NET Core 2.1 になって、Linux と Windows の処理速度にやっと差がなくなりました。また、.NET Core と .NET Framework との処理時間もほぼ同じなりました。やっと、Linux で C# が使えるようになったといいでしょう。しかしながら、.NET Framework 4.5が公開されたのが2012年8月なので6年かかったということになります。競争相手のJavaにはKotlinという新しい言語が出てきたし、その間にJavaScriptは大きく進歩してしまいました。遅すぎたというのが現実だと思います。

Pythonの方は、Windowsで使うと3割ぐらいも遅くなるという結果になりました。PythonをWindowsで使うと遅くなるのは以前からでしたが、Python3.7が公開されたばかりなのでバイナリーの方がまだ十分に対応していないためというのもあると思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away