pandasデータフレームがあります(これはほんの一部です)
>>> d1
y norm test y norm train len(y_train) len(y_test) \
0 64.904368 116.151232 1645 549
1 70.852681 112.639876 1645 549
SVR RBF \
0 (35.652207342877873, 22.95533537448393)
1 (39.563683797747622, 27.382483096332511)
LCV \
0 (19.365430594452338, 13.880062435173587)
1 (19.099614489458364, 14.018867136617146)
RIDGE CV \
0 (4.2907610988480362, 12.416745648065584)
1 (4.18864306788194, 12.980833914392477)
RF \
0 (9.9484841581029428, 16.46902345373697)
1 (10.139848213735391, 16.282141345406522)
GB \
0 (0.012816232716538605, 15.950164822266007)
1 (0.012814519804493328, 15.305745202851712)
ET DATA
0 (0.00034337162272515505, 16.284800366214057) j2m
1 (0.00024811554516431878, 15.556506191784194) j2m
>>>
タプルを含むすべての列を分割したい。たとえば、列LCV
を列LCV-a
およびLCV-b
に置き換えます。
どうやってやるの?
より大きなデータセットでは、.apply()
はpd.DataFrame(df['b'].values.tolist(), index=df.index)
よりも数桁遅いことがわかりました。
この決定はGitHubで解決されましたが、この決定には同意しません。
https://github.com/pandas-dev/pandas/issues/11615
編集:この回答に基づいて: https://stackoverflow.com/a/44196843/2230844
私はこれが少し前からであることを知っていますが、2番目の解決策の警告:
pd.DataFrame(df['b'].values.tolist())
明示的にインデックスを破棄し、デフォルトのシーケンシャルインデックスを追加しますが、受け入れられた答えは
apply(pd.Series)
適用の結果は行インデックスを保持するため、そうはなりません。順序は元の配列から最初に保持されますが、pandasは2つのデータフレームのインデックスを一致させようとします。
これは、行を数値インデックス付き配列に設定しようとする場合に非常に重要になる可能性があり、pandasは新しい配列のインデックスを古い配列に自動的に一致させ、順序に歪みを生じさせます。
より良いハイブリッドソリューションは、元のデータフレームのインデックスを新しいデータセットに設定することです。
pd.DataFrame(df['b'].values.tolist(), index=df.index)
結果に対して順序とインデックスが保持されるようにしながら、2番目の方法を使用する速度を保持します。
私はもっと簡単な方法だと思う:
>>> import pandas as pd
>>> df = pd.DataFrame({'a':[1,2], 'b':[(1,2), (3,4)]})
>>> df
a b
0 1 (1, 2)
1 2 (3, 4)
>>> df['b_a']=df['b'].str[0]
>>> df['b_b']=df['b'].str[1]
>>> df
a b b_a b_b
0 1 (1, 2) 1 2
1 2 (3, 4) 3 4
pandas.Series
のdtype == object
オブジェクトで使用可能なstr
アクセサーは、実際には反復可能です。
pandas.DataFrame
df
を想定:
df = pd.DataFrame(dict(col=[*Zip('abcdefghij', range(10, 101, 10))]))
df
col
0 (a, 10)
1 (b, 20)
2 (c, 30)
3 (d, 40)
4 (e, 50)
5 (f, 60)
6 (g, 70)
7 (h, 80)
8 (i, 90)
9 (j, 100)
反復可能かどうかをテストできます
from collections import Iterable
isinstance(df.col.str, Iterable)
True
その後、他のイテラブルを行うように、そこから割り当てることができます。
var0, var1 = 'xy'
print(var0, var1)
x y
したがって、1行で両方の列を割り当てることができます
df['a'], df['b'] = df.col.str
df
col a b
0 (a, 10) a 10
1 (b, 20) b 20
2 (c, 30) c 30
3 (d, 40) d 40
4 (e, 50) e 50
5 (f, 60) f 60
6 (g, 70) g 70
7 (h, 80) h 80
8 (i, 90) i 90
9 (j, 100) j 100
少しだけ複雑ですが、Zip
を使用して同様の反復可能オブジェクトを作成できます
df['c'], df['d'] = Zip(*df.col)
df
col a b c d
0 (a, 10) a 10 a 10
1 (b, 20) b 20 b 20
2 (c, 30) c 30 c 30
3 (d, 40) d 40 d 40
4 (e, 50) e 50 e 50
5 (f, 60) f 60 f 60
6 (g, 70) g 70 g 70
7 (h, 80) h 80 h 80
8 (i, 90) i 90 i 90
9 (j, 100) j 100 j 100
つまり、既存のdf
を変更しないでください
これは、assign
がキーワード引数を取り、キーワードが新しい(または既存の)列名であり、値が新しい列の値になるため、機能します。辞書を使用し、**
で展開して、キーワード引数として機能させることができます。したがって、これは'g'
iterableの最初の項目であるdf.col.str
という名前の新しい列と、'h'
iterableの2番目の項目であるdf.col.str
という名前の新しい列を割り当てる賢い方法です。
df.assign(**dict(Zip('gh', df.col.str)))
col g h
0 (a, 10) a 10
1 (b, 20) b 20
2 (c, 30) c 30
3 (d, 40) d 40
4 (e, 50) e 50
5 (f, 60) f 60
6 (g, 70) g 70
7 (h, 80) h 80
8 (i, 90) i 90
9 (j, 100) j 100
list
アプローチの私のバージョン最新のリストの理解と変数の展開。
注:join
を使用してインラインでも
df.join(pd.DataFrame([*df.col], df.index, [*'ef']))
col g h
0 (a, 10) a 10
1 (b, 20) b 20
2 (c, 30) c 30
3 (d, 40) d 40
4 (e, 50) e 50
5 (f, 60) f 60
6 (g, 70) g 70
7 (h, 80) h 80
8 (i, 90) i 90
9 (j, 100) j 100
変異バージョンは
df[['e', 'f']] = pd.DataFrame([*df.col], df.index)
上記で定義されたものを使用
%timeit df.assign(**dict(Zip('gh', df.col.str)))
%timeit df.assign(**dict(Zip('gh', Zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))
1.16 ms ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
635 µs ± 18.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
795 µs ± 42.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
10 ^ 3倍
df = pd.concat([df] * 1000, ignore_index=True)
%timeit df.assign(**dict(Zip('gh', df.col.str)))
%timeit df.assign(**dict(Zip('gh', Zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))
11.4 ms ± 1.53 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.1 ms ± 41.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.33 ms ± 35.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)