1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【備忘録】Pythonイディオム(from DataFrame to List)

Last updated at Posted at 2020-08-26

はじめに

フロントエンド(highchats)にデータを渡すAPI(python製)を自作する際、
Dataframe (pandas) からlist (二次元リスト) に変形する処理を
実装する機会が、とても増えました。
今回、備忘録も兼ねて、自分なりに良いと思ったコードを紹介したいと思います。
また、検討する際に、行った速度実験結果も示します。

環境 (Python関連)

python 3.7.4
pandas 0.25.3

コード

1. to_numpy().tolist()

# df:DataFrame
df.to_numpy().tolist()

これが、一番シンプルな方法で、
多くの場合は、これで問題ないです。
しかし、ある環境下では、次のような問題が起きます。

2. to_numpy().tolist()の問題点

生じる問題というのは、
型変換 (int → float) が自動的に起きることです。
具体例は、下記のとおりです。(下記は公式ドキュメントを引用)

>>> df = pd.DataFrame({"A": [1, 2], "B": [3.0, 4.5]})
>>> df.to_numpy()
array([[1. , 3. ],
       [2. , 4.5]])

上記のA列に注目すると、
float型に自動変換されていることが分かると思います。(11. , 22.)
このような自動変換処理が起きる条件は、
DataFrameの列の型が、int型とfloat型のみで構成されている場合に起きています。
実際、下記の例のように、DateTime型が入れば、保存されていることが分かります。
(下記も公式ドキュメントを引用)

>>> df['C'] = pd.date_range('2000', periods=2)
>>> df.to_numpy()
array([[1, 3.0, Timestamp('2000-01-01 00:00:00')],
       [2, 4.5, Timestamp('2000-01-02 00:00:00')]], dtype=object)

したがって、次からは、
int,floatのみに起きる型の自動変換する問題を
解決できるコード例を3つ挙げていきます。

3. 解決方法1 (zipを用いた内包表現)

#df:DataFrame
list(map(list,zip(*[s[1].tolist() for s in df.items()])))

上記のコードは理解しにくいと思いますので、
以下に処理フローを示しています。

  1. df.items()は1行毎のSeriesを返すイテレーターになります。
  2. zip関数によって、1列ごとのタプルを返すイテレータになります。
  3. map関数list関数によって、二次元リストができます。

3つの例中、一番可読性の低いコードになっております・・・

4. 解決方法2 (to_numpy & 内包表現)

#df:DataFrame
[array.tolist() for array in df.astype('object').to_numpy()]

ここでのポイントは、**astype('object')**です。
DataFrameの型を無理やり、object型にすると、
int型が維持されていることを見つけました。
(正直、この維持される理由を、しっくり来る説明ができてないです・・・)

5. 解決方法3 (to_dict)

#df:DataFrame
df.to_dict('split')['data']

これは3例の中で、一番シンプルになっています。
ですので、公式ドキュメントを見てもらえば、分かると思います。

速度実験 (内包表現 vs to_dict)

続いて、3例の実行速度計測してみました。
計測に用いたDataframeは、910行 ✕ 4列 (int型が1列, float型が3列)です。
解決方法1:   230 ± 16 μs
解決方法2:   820 ± 40 μs
解決方法3:  2020 ± 64 μs

一番早い方法は、一番複雑だったzipを用いた内包表記になりました。
私としては、全く予想外の結果でした。
複雑のことをしていたので、遅くなるかなと思っていたので。
さらに、zip関数は、速いということを、気づくことができました。

まとめ

DataFrameから二重リストを作る際には、
基本方針は、df.to_numpy().tolist()
int,floatの2種類構成の場合、zipを用いた内包表記を使っていこうかと思います。
ただし、このコードの可読性は低いのが、一番の課題です。

1
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?