🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

4回答

5023閲覧

pandasを高速化したいです

nouken

総合スコア369

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

2クリップ

投稿2019/09/27 11:05

python

1import pandas as pd 2df = pd.DataFrame() 3df["column"] = [["a", "c", "e"], ["b"], ["c", "e"], ["a", "e"], ["a", "b", "c"]] 4df.head() 5 6>> column 70 [a, c, e] 81 [b] 92 [c, e] 103 [a, e] 114 [a, b, c]

のようなデータフレームがあるとします。

<やりたいこと>
columnの取りうる値全てに対して、それぞれ各行に対してバイナリーの変数に変換したいです。
つまり
|a|b|c|d|e|
|:--:|:--:|--:|
|1|0|1|0|1|
|0|1|0|0|0|
|0|0|1|0|1|
|1|0|0|0|1|
|1|1|1|0|0|

を得たいです。

<試したこと>
uniqは取りうる値を格納しています。

python

1for col in uniq: 2 df[col] = 0 3 4 for i in range(len(df)): 5 if col in df.loc[i, "column"]: 6 df.loc[i, col] = 1 7 else: 8 df.loc[i, col] = 0 9

<解決したいこと>

実際に扱っているデータフレームは三万行くらいで、取りうる値は10個くらいであり、
かなり遅いです。
実際にはこの操作を複数回行う必要があり、上の操作を高速化する必要があります。
お力添えいただけないでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

コードは汚いですがcolumnの各文字列を数値化してnumpyでフラグ配列化すると速いです。
参考:Convert integer to binary array with suitable padding

Python

1import pandas as pd 2import random 3import numpy as np 4 5# テストデータ 6CHARS = 'abcdefghij' # 'abc'など 7N = 30000 # 5など 8lst = [] 9for i in range(N): 10 lst.append(random.sample(CHARS,random.randint(1,len(CHARS)))) 11df = pd.DataFrame({"column":lst}) 12 13# テストデータ 14df = pd.DataFrame({"column":[["a", "c", "e"], ["b"], ["c", "e"], ["a", "e"], ["a", "b", "c"]]}) 15print(df) 16 17# 18# ['b','a','c] -> 1+2+4 = 7 19# ['a'] -> 2 = 2 20# のように文字列の出現順に数値化 21# 22txt2bin = {} # 'a'-> 2 など 23bin = 1 24def f(l): 25 global bin 26 n = 0 27 for c in l: 28 if c not in txt2bin: 29 txt2bin[c] = bin 30 bin <<= 1 31 n += txt2bin[c] 32 return n 33 34a = df['column'].apply(f).values 35 36# 数値->フラグ配列化 37b = (((a[:,None] & (1 << np.arange(len(txt2bin))))) > 0).astype(int) 38 39# フラグ配列の並び順に列名を並べる 40columns = sorted(txt2bin.items(), key=lambda e:e[1]) 41columns = [ v[0] for v in columns] 42 43ret = pd.DataFrame(b, columns=columns) 44 45# 列名を昇順に 46ret = ret.loc[:,sorted(columns)] 47print(ret) 48""" 49 a b c e 500 1 0 1 1 511 0 1 0 0 522 0 0 1 1 533 1 0 0 1 544 1 1 1 0 55"""

投稿2019/09/28 02:22

編集2019/09/28 08:11
can110

総合スコア38341

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

siruku6

2019/09/28 07:17

きっと早いのだと思いますが、あとあと修正するかもしれないことを考えると、この方法を使用する決断はしにくいですね。 でも非常に勉強になります。
can110

2019/09/28 08:17

実際に速いです。修正内容にもよるかと思うので採用できないのは残念ですが 100万行でもほぼ一瞬なので速度面ではメリットあるかと思います。
siruku6

2019/09/28 08:36

本当に速度が重要なシステムだったら、多少可読性を犠牲にしてでもこういった方法を使用した方がいいのでしょうね。 ベストアンサーの回答も相当早そうなので、もし必要になったら実際の要件に従って実装して、速度比較ですね。
guest

0

ベストアンサー

ループなし、ワンライナーで書いてみました。
やってることは

  1. リストをセルに分割
  2. stack() で縦に並べ替え
  3. pandas.get_dummies()でOne-Hot化
  4. 元のIndex番号同志で結合(sum()

です

Python

1import pandas as pd 2df = pd.DataFrame({"column":[["a", "c", "e"], ["b"], ["c", "e"], ["a", "e"], ["a", "b", "c"]]}) 3ret = pd.get_dummies(df['column'].apply(pd.Series).stack()).groupby(level=0).apply(sum) 4# a b c e 5#0 1 0 1 1 6#1 0 1 0 0 7#2 0 0 1 1 8#3 1 0 0 1 9#4 1 1 1 0

投稿2019/09/27 13:59

magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

siruku6

2019/09/27 23:00 編集

このやり方の方が圧倒的に早いですね! 何万行あってもすぐに終わるのではないでしょうか、、
nouken

2019/09/29 05:50

10秒ほどでいけました。ありがとうございました〜
guest

0

dataframeをfor文の中で使用すると死ぬほど遅いです。
吐き気がするほどに。

ですので、どうしてもloop処理したいのであれば、辞書型などに変換してしまうのがおすすめです。
(可読性は下がりますが...)

python

1import pandas as pd 2 3# データの準備 4df = pd.DataFrame() 5df["column"] = [["a", "c", "e"], ["b"], ["c", "e"], ["a", "e"], ["a", "b", "c"]] 6uniq = ['a', 'b', 'c', 'd', 'e'] 7 8# メインのloop処理 9dict_results = [] 10for items in df.to_dict()['column'].values(): 11 tmp_dict_result = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0} 12 for col in uniq: 13 if col in items: 14 tmp_dict_result[col] = 1 15 dict_results.append(tmp_dict_result) 16 17pd.DataFrame.from_dict(dict_results)

ただし、numpy配列化すればベクトル演算ができるので、もっと高速にできるかもしれません。
誰か知ってませんかね....(私も知りたいです)

投稿2019/09/27 12:30

編集2019/09/27 12:31
siruku6

総合スコア1382

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

バイナリが良くわからないので会っているか分かりませんが

python

1df.astype(bytes)

型の変換だけならこうだと思います

投稿2019/09/27 11:17

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nouken

2019/09/27 11:28

すみません、型の変換ではなく、元の変数を上にあるように、0,1の変数に変換したいということです。文脈としては機械学習の前処理になります。
退会済みユーザー

退会済みユーザー

2019/09/27 11:32

df.astype(bool) df.astype(int) 多分違いますが これでも01にできますよ
nouken

2019/09/27 11:38

ありがとうございます。上の例のように、元の変数がリストなのです。。。
退会済みユーザー

退会済みユーザー

2019/09/27 11:58

そうですか 理解不足ですいません あまり扱わない形式なので わかんないかもです
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問