web-dev-qa-db-ja.com

pandas DataFrameの列の.str.split()操作後の最後の「列」を取得

pandas DataFrameに1つのスペースで分割したい列があります。分割はDataFrame.str.split(' ')で十分簡単ですが、新しく作成することはできません。最後のエントリからの列。.str.split()列を取得すると、配列のリストを取得しますが、これを操作してDataFrameの新しい列を取得する方法がわかりません。

以下に例を示します。列の各エントリには「シンボルデータ価格」が含まれており、価格を分割します(最終的には半分のケースで「p」...または「c」を削除します)。

import pandas as pd
temp = pd.DataFrame({'ticker' : ['spx 5/25/2001 p500', 'spx 5/25/2001 p600', 'spx 5/25/2001 p700']})
temp2 = temp.ticker.str.split(' ')

をもたらす

0    ['spx', '5/25/2001', 'p500']
1    ['spx', '5/25/2001', 'p600']
2    ['spx', '5/25/2001', 'p700']

しかし、temp2[0]は、1つのリストエントリの配列とtemp2[:][-1]は失敗します。各配列の最後のエントリを新しい列に変換するにはどうすればよいですか?ありがとう!

43
Richard Herron

tolistメソッドを仲介として使用できます。

In [99]: import pandas as pd

In [100]: d1 = pd.DataFrame({'ticker' : ['spx 5/25/2001 p500', 'spx 5/25/2001 p600', 'spx 5/25/2001 p700']})

In [101]: d1.ticker.str.split().tolist()
Out[101]: 
[['spx', '5/25/2001', 'p500'],
 ['spx', '5/25/2001', 'p600'],
 ['spx', '5/25/2001', 'p700']]

新しいDataFrameを作成できる場所:

In [102]: d2 = pd.DataFrame(d1.ticker.str.split().tolist(), 
   .....:                   columns="symbol date price".split())

In [103]: d2
Out[103]: 
  symbol       date price
0    spx  5/25/2001  p500
1    spx  5/25/2001  p600
2    spx  5/25/2001  p700

適切な方法として、価格を修正できます。

In [104]: d2["price"] = d2["price"].str.replace("p","").astype(float)

In [105]: d2
Out[105]: 
  symbol       date  price
0    spx  5/25/2001    500
1    spx  5/25/2001    600
2    spx  5/25/2001    700

PS:しかし、reallyが最後の列だけが必要な場合は、applyで十分です:

In [113]: temp2.apply(lambda x: x[2])
Out[113]: 
0    p500
1    p600
2    p700
Name: ticker
34
DSM

これを行う:

In [43]: temp2.str[-1]
Out[43]: 
0    p500
1    p600
2    p700
Name: ticker
93
Wes McKinney

https://pandas.pydata.org/pandas-docs/stable/text.html

s2 = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'])
s2.str.split('_').str.get(1)

または

s2.str.split('_').str[1]
15
James Holland

Pandas 0.20.3を使用:

In [10]: import pandas as pd
    ...: temp = pd.DataFrame({'ticker' : ['spx 5/25/2001 p500', 'spx 5/25/2001 p600', 'spx 5/25/2001 p700']})
    ...:

In [11]: temp2 = temp.ticker.str.split(' ', expand=True)  # the expand=True return a DataFrame

In [12]: temp2
Out[12]:
     0          1     2
0  spx  5/25/2001  p500
1  spx  5/25/2001  p600
2  spx  5/25/2001  p700

In [13]: temp3 = temp.join(temp2[2])

In [14]: temp3
Out[14]:
               ticker     2
0  spx 5/25/2001 p500  p500
1  spx 5/25/2001 p600  p600
2  spx 5/25/2001 p700  p700
3
AllanLRH

_Series.str.rpartition_

非常に効率的です。

_temp.ticker.str.rpartition(expand=False).str[-1]

0    p500
1    p600
2    p700
Name: ticker, dtype: object
_

_expand=True_(デフォルト)を渡すと、結果はDataFrameになり、各列は独自の分割に属します。

_temp.ticker.str.rpartition()
# temp.ticker.str.rpartition(expand=True)

               0  1     2
0  spx 5/25/2001     p500
1  spx 5/25/2001     p600
2  spx 5/25/2001     p700
_

ここから、最後の列を取得するのは簡単です。

_temp.ticker.str.rpartition().iloc[:,-1]

0    p500
1    p600
2    p700
Name: 2, dtype: object
_

Series.str.rsplit(n=1)

別の提案は_str.rsplit_です。最後から分割するので、splitに一度だけ分割するように要求できます(最終分割の前に何も必要ないため)。

_temp.ticker.str.rsplit(n=1).str[-1]

0    p500
1    p600
2    p700
Name: ticker, dtype: object
_

または、

_temp.ticker.str.rsplit(n=1, expand=True).iloc[:,-1]

0    p500
1    p600
2    p700
Name: 1, dtype: object
_

これは_str.split_よりも効率的であることがわかりました。


リストの理解

パフォーマンスのために、ここでリスト内包表記を使用できます。

_[s.rpartition(' ')[-1] for s in temp.ticker]
# ['p500', 'p600', 'p700']

pd.Series([s.rpartition(' ')[-1] for s in temp.ticker])

0    p500
1    p600
2    p700
dtype: object
_

リストcompで_str.rsplit_を使用することもできます。

_pd.Series([s.rsplit(None, 1)[-1] for s in temp.ticker])

0    p500
1    p600
2    p700
dtype: object
_

リストの内包表記は、pandas文字列関数よりもオーバーヘッドが少ないため、リスト内包表記をお勧めします(これもデータを反復処理します。 pandas-いつ気にしますか? のForループ。


性能

_df_ = temp.copy()
df = pd.concat([df_] * 10000, ignore_index=True)

%timeit df.ticker.str.split().str[-1]
%timeit df.ticker.str.rpartition().iloc[:,-1]
%timeit df.ticker.str.rsplit(n=1).str[-1]
%timeit pd.Series([s.rpartition(' ')[-1] for s in df.ticker])
%timeit pd.Series([s.rsplit(None, 1)[-1] for s in df.ticker])

72.4 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
54.9 ms ± 1.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
65.2 ms ± 1.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
20.4 ms ± 334 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
26.5 ms ± 1.53 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
_

リスト内包表記法は高速ですが、シリーズへの変換のオーバーヘッドが原因で、ほとんどの速度が低下します。生リストのコンプ操作ははるかに高速です。

_%timeit [s.rpartition(' ')[-1] for s in df.ticker]
18 ms ± 289 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
_
0
coldspeed