データ構造

このチュートリアルでは、値の読み込み・書き込み時における一般的な事例やxlwingsのデフォルトの動作を簡単に紹介します。options メソッドの使い方についてのより詳しい説明は コンバーターおよびオプション をご覧ください。

これ以降のすべてのコード サンプルは次のインポートを前提としています:

>>> import xlwings as xw

単独セル

デフォルトでは単独セルは、セルの値が数字であれば float、文字列であれば unicode 、空(empty)であれば None 、日付であれば datetime として読み込まれます。

>>> import datetime as dt
>>> sheet = xw.Book().sheets[0]
>>> sheet.range('A1').value = 1
>>> sheet.range('A1').value
1.0
>>> sheet.range('A2').value = 'Hello'
>>> sheet.range('A2').value
'Hello'
>>> sheet.range('A3').value is None
True
>>> sheet.range('A4').value = dt.datetime(2000, 1, 1)
>>> sheet.range('A4').value
datetime.datetime(2000, 1, 1, 0, 0)

リスト

  • 1次元リスト: Excel上で行または列形式のRangeは、単純なリスト形式で読み込まれます。したがって、一度Pythonに読み込まれると元の形状(行であるか列であるか)がわからなくなります。このことが問題となるようなら、次の・で紹介するの方法をとりましょう:

    >>> sheet = xw.Book().sheets[0]
    >>> sheet.range('A1').value = [[1],[2],[3],[4],[5]]  # Column orientation (nested list)
    >>> sheet.range('A1:A5').value
    [1.0, 2.0, 3.0, 4.0, 5.0]
    >>> sheet.range('A1').value = [1, 2, 3, 4, 5]
    >>> sheet.range('A1:E1').value
    [1.0, 2.0, 3.0, 4.0, 5.0]
    

    単独セルを強制的にリストとして読み込む方法は次のとおりです:

    >>> sheet.range('A1').options(ndim=1).value
    [1.0]
    

    注釈

    To write a list in column orientation to Excel, use transpose: sheet.range('A1').options(transpose=True).value = [1,2,3,4]

  • 2次元リスト: 行や列の方向を保持するには、Rangeのオプションで ndim を使います。こうすれば、Rangeは入れ子のリスト("2次元リスト")として読み込まれます:

    >>> sheet.range('A1:A5').options(ndim=2).value
    [[1.0], [2.0], [3.0], [4.0], [5.0]]
    >>> sheet.range('A1:E1').options(ndim=2).value
    [[1.0, 2.0, 3.0, 4.0, 5.0]]
    
  • 2次元のRangeは自動的に入れ子のリストとして読み込まれます。逆に(入れ子の)リストをExcelのRangeに代入するには、左上のセルを指定します。次の例では、値をPythonに読み込む時のインデックスの使い方も示しています:

    >>> sheet.range('A10').value = [['Foo 1', 'Foo 2', 'Foo 3'], [10, 20, 30]]
    >>> sheet.range((10,1),(11,3)).value
    [['Foo 1', 'Foo 2', 'Foo 3'], [10.0, 20.0, 30.0]]
    

注釈

Try to minimize the number of interactions with Excel. It is always more efficient to do sheet.range('A1').value = [[1,2],[3,4]] than sheet.range('A1').value = [1, 2] and sheet.range('A2').value = [3, 4].

Rangeの拡張

expand メソッドか options メソッドの expand キーワードを使えば、ExcelのRangeをサイズに応じて動的に取得ができます。 expand メソッドは拡張されたRangeオブジェクトを返すのに対し、 options メソッドはRangeの値を取得する時のみ評価されます。次の例を見ればその違いがわかるでしょう:

>>> sheet = xw.Book().sheets[0]
>>> sheet.range('A1').value = [[1,2], [3,4]]
>>> rng1 = sheet.range('A1').expand('table')  # or just .expand()
>>> rng2 = sheet.range('A1').options(expand='table')
>>> rng1.value
[[1.0, 2.0], [3.0, 4.0]]
>>> rng2.value
[[1.0, 2.0], [3.0, 4.0]]
>>> sheet.range('A3').value = [5, 6]
>>> rng1.value
[[1.0, 2.0], [3.0, 4.0]]
>>> rng2.value
[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]

'table' は行および列方向、'down' は行方向、 'right' は列方向に拡張します。

注釈

Using expand() together with a named Range as top left cell gives you a flexible setup in Excel: You can move around the table and change its size without having to adjust your code, e.g. by using something like sheet.range('NamedRange').expand().value.

NumPy arrays

Numpy arrayは、入れ子のリストと同様に機能します。ただし、空のセルは None ではなく nan となります。RangeをNumpy arrayとして読み込むには、options メソッドで convert=np.array を指定します:

>>> import numpy as np
>>> sheet = xw.Book().sheets[0]
>>> sheet.range('A1').value = np.eye(3)
>>> sheet.range('A1').options(np.array, expand='table').value
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

Pandas DataFrames

>>> sheet = xw.Book().sheets[0]
>>> df = pd.DataFrame([[1.1, 2.2], [3.3, None]], columns=['one', 'two'])
>>> df
   one  two
0  1.1  2.2
1  3.3  NaN
>>> sheet.range('A1').value = df
>>> sheet.range('A1:C3').options(pd.DataFrame).value
   one  two
0  1.1  2.2
1  3.3  NaN
# options: work for reading and writing
>>> sheet.range('A5').options(index=False).value = df
>>> sheet.range('A9').options(index=False, header=False).value = df

Pandas Series

>>> import pandas as pd
>>> import numpy as np
>>> sheet = xw.Book().sheets[0]
>>> s = pd.Series([1.1, 3.3, 5., np.nan, 6., 8.], name='myseries')
>>> s
0    1.1
1    3.3
2    5.0
3    NaN
4    6.0
5    8.0
Name: myseries, dtype: float64
>>> sheet.range('A1').value = s
>>> sheet.range('A1:B7').options(pd.Series).value
0    1.1
1    3.3
2    5.0
3    NaN
4    6.0
5    8.0
Name: myseries, dtype: float64

注釈

You only need to specify the top left cell when writing a list, a NumPy array or a Pandas DataFrame to Excel, e.g.: sheet.range('A1').value = np.eye(10)

Chunking: Read/Write big DataFrames etc.

When you read and write from or to big ranges, you may have to chunk them or you will hit a timeout or a memory error. The ideal chunksize will depend on your system and size of the array, so you will have to try out a few different chunksizes to find one that works well:

import pandas as pd
import numpy as np
sheet = xw.Book().sheets[0]
data = np.arange(75_000 * 20).reshape(75_000, 20)
df = pd.DataFrame(data=data)
sheet['A1'].options(chunksize=10_000).value = df

And the same for reading:

# As DataFrame
df = sheet['A1'].expand().options(pd.DataFrame, chunksize=10_000).value
# As list of list
df = sheet['A1'].expand().options(chunksize=10_000).value