2016-01-13 2 views
7

私は検索を試してきましたが、これを行う簡単な方法がわからないので、あなたの専門知識が役立つことを望んでいます。Python Pandasは別の列を使って部分文字列を取り除いています

私は私がやりたいものを私に

  FULL_NAME NAME 
0  FIRST LAST FIRST 
1    NaN NaN 
2  FIRST LAST NAME2 
3  FIRST NAME3 NAME3 
4 FIRST NAME4 LAST NAME4 
5  ANOTHER NAME NAME5 
6   LAST NAME NAME6 

を与える二つの列

import numpy as np 
import pandas as pd 

pd.options.display.width = 1000 
testing = pd.DataFrame({'NAME':[ 
    'FIRST', np.nan, 'NAME2', 'NAME3', 
    'NAME4', 'NAME5', 'NAME6'], 'FULL_NAME':['FIRST LAST', np.nan, 'FIRST LAST', 'FIRST NAME3', 'FIRST NAME4 LAST', 'ANOTHER NAME', 'LAST NAME']}) 

とパンダのデータフレームを持っているが「NAME」列から値を取得し、その後削除されそこにある場合は 'フルネーム'列から削除してください。したがって、関数は返されます

  FULL_NAME NAME   NEW 
0  FIRST LAST FIRST   LAST 
1    NaN NaN   NaN 
2  FIRST LAST NAME2 FIRST LAST 
3  FIRST NAME3 NAME3   FIRST 
4 FIRST NAME4 LAST NAME4 FIRST LAST 
5  ANOTHER NAME NAME5 ANOTHER NAME 
6   LAST NAME NAME6  LAST NAME 

これまでの関数を定義し、applyメソッドを使用しています。これは私の大規模なデータセットではむしろ遅く実行され、私はそれを行うより効率的な方法があることを望んでいます。ありがとう!ここで

def address_remove(x): 
    try: 
     newADDR1 = re.sub(x['NAME'], '', x[-1]) 
     newADDR1 = newADDR1.rstrip() 
     newADDR1 = newADDR1.lstrip() 
     return newADDR1 
    except: 
     return x[-1] 

答えて

4

がかなり速くあなたの現在のソリューションよりも一つの解決策がある、私は

In [13]: import numpy as np 
     import pandas as pd 
     n = 1000 
     testing = pd.DataFrame({'NAME':[ 
     'FIRST', np.nan, 'NAME2', 'NAME3', 
     'NAME4', 'NAME5', 'NAME6']*n, 'FULL_NAME':['FIRST LAST', np.nan, 'FIRST LAST', 'FIRST NAME3', 'FIRST NAME4 LAST', 'ANOTHER NAME', 'LAST NAME']*n}) 

これは長いものの一種ですが、より高速なものがないだろうと確信していません

In [37]: %timeit testing ['NEW2'] = [e.replace(k, '') for e, k in zip(testing.FULL_NAME.astype('str'), testing.NAME.astype('str'))] 
100 loops, best of 3: 4.67 ms per loop 
:ライナーが、それはあなたが、私は別の答えで述べたように replaceを使用しているを考え出すことができる

絶食ソリューションを必要とする何をすべき

オリジナルの答え:あなたの現在のソリューションに比べ

In [14]: %timeit testing ['NEW'] = [''.join(str(e).split(k)) for e, k in zip(testing.FULL_NAME.astype('str'), testing.NAME.astype('str'))] 
100 loops, best of 3: 7.24 ms per loop 

In [16]: %timeit testing['NEW1'] = testing.apply(address_remove, axis=1) 
10 loops, best of 3: 166 ms per loop 

これらは、あなたの現在のソリューションとして、あなたに同じ答えを得る

+0

素晴らしい!私は第2の解決策を考案しようとしていましたが、第3の解決策はさらに優れています!あなたは "zip"コマンドが何をしているのか教えていただけますか? – Link

+0

うれしかった! 'zip'は複数のiterableを取り、元のiterablesから集約のイテレータを返します。より多くの条件では、2つ以上の繰り返し可能なループを同時に実行することができます。 https://docs.python.org/3/library/functions.html#zip – johnchase

0

私はあなたが(置き換える使用したいと思います)メソッドは、文字列の場合、正規表現を使用するよりもはるかに高速です(私はIPythonですぐにチェックしました):

%timeit mystr.replace("ello", "") 
The slowest run took 7.64 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 250 ns per loop 

%timeit re.sub("ello","", "e") 
The slowest run took 21.03 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 4.7 µs per loop 

それ以降の速度の改善が必要な場合は、numpyのvectorize関数を調べる必要があります(しかし、正規表現の代わりにreplaceを使用することによるスピードアップは相当なものになるはずです)。

2

あなたはreplace方法とregex引数でそれを行うと、その後str.strip使用することができますあなたは空の文字列

に置き換えられますので、また、それ NaN値なし testing.NAMEから notnullを渡す必要があり

In [605]: testing.FULL_NAME.replace(testing.NAME[testing.NAME.notnull()], '', regex = True).str.strip() 
Out[605]: 
0   LAST 
1    NaN 
2  FIRST LAST 
3   FIRST 
4  FIRST LAST 
5 ANOTHER NAME 
6  LAST NAME 
Name: FULL_NAME, dtype: object 

注意

ベンチマーキングは、最も遅い@johnchaseソリューションですが、私はそれがより読みやすく、すべてのパンダを使用すると考えていますデータフレームとシリーズのods:

In [607]: %timeit testing['NEW'] = testing.FULL_NAME.replace(testing.NAME[testing.NAME.notnull()], '', regex = True).str.strip() 
100 loops, best of 3: 4.56 ms per loop 

In [661]: %timeit testing ['NEW'] = [e.replace(k, '') for e, k in zip(testing.FULL_NAME.astype('str'), testing.NAME.astype('str'))] 
1000 loops, best of 3: 450 µs per loop 
+0

純粋なパンダソリューション。よくできました。たとえそれが速くなくても、読んでも間違いありません。 – floydn

+0

あなたのコードで 'df'を' testing'にする必要がありますか? – johnchase

+0

@johnchaseはい、申し訳ありません。それはコンソールでの入力が少なくて済む –