2017-08-23 10 views
1

私は複数の列を持つデータフレームを持っています。私は各行に優先度を割り当てたい。 この優先順位は、他の列のデータに基づいて与えられます。パンダ:他の複数の列に基づいて列を作成します。適用失敗()

私は

def priority(Bcat,Brand,IPC,Customer, Type): 
    p=1 
    if Bcat != "*": 
     p+= len(Bcat)/3 
    if Brand != "*": 
     p+= 2 
    if IPC != "*": 
     p+= 4 
    if Customer != "*" & Customer != "REPLCUST": 
     p+= 8 
    if Type == "Default": 
     p+= -16 
    return p 

優先機能を定義していると私は私のデータフレームに適用するために、今したいです。

これは私のデータフレームは、(2500行)のようになります。

Bcat Brand Customer IPC LOC MKT_BUD  Type STARTEFF Value 
A B  C   D  E F   1  2001-01-01 1.0 

私はこれをしようとしていますが、それは

df["Priority"] = df[["Bcat","Brand","IPC","Customer","Type"]].apply(priority,axis=1,args=("Bcat","Brand","IPC","Customer","Type")) 

機能しないと、私はこのメッセージ

TypeError: ('priority() takes 5 positional arguments but 6 were given', 'occurred at index 0') 
を取得

これも試しました

df["Priority"] = np.vectorize(priority(df.Bcat,df.Brand,df.IPC,df.Customer,df.Type)) 

と、このメッセージ

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all(). 

答えて

3

を持って、あなたのデータフレームに適用を使用する場合は、ラムダ関数が必要になる場合があります:これは、データフレーム上で動作します

def priority(Bcat,Brand,IPC,Customer, Type): 
    p=1 
    if Bcat != "*": 
     p+= len(Bcat)/3 
    if Brand != "*": 
     p+= 2 
    if IPC != "*": 
     p+= 4 
    if (Customer != "*") & (Customer != "REPLCUST"): # Here you need brackets 
     p+= 8 
    if Type == "Default": 
     p+= -16 
    return p 

df= pd.DataFrame([['A','B','C','D','E','F','1','2001-01-01','1.0']],\ 
    columns = ['Bcat','Brand','Customer','IPC','LOC','MKT_BUD','Type','STARTEFF','Value']) 

df.apply(lambda x: priority(x.Bcat,x.Brand,x.IPC,x.Customer,x.Type),axis = 1) 

0 15.333333 
dtype: float64 

をので、おそらくではありません文字列の長さにアクセスするために行全体をループするので最適です。df.BCat。もっと効率的なものを探します。

EDIT:

そうしないと、列方向操作を実行するためにstr.lenを使用することができますあなたが行をループするのではなく、シリーズ上で動作するよう

df['priority'] = 1 
mask = df.Bcat != "*" 
df.loc[mask,'priority'] += df.loc[mask,'Bcat'].str.len()/3 
df.loc[df.Brand != "*",'priority'] += 2 
df.loc[df.IPC != "*",'priority'] += 4 
df.loc[~df.Customer.isin(['*','REPLCUST']),'priority'] += 8 
df.loc[df.Type == "Default",'priority'] -= 16 

    Bcat Brand Customer IPC LOC MKT_BUD Type STARTEFF Value priority 
0 A  B  C   D E F  1  2001-01-01 1.0 15.333333 

これは、より高速な方法となります。

+0

私はすべての解決策を検討しましたが、実装が最も速くなると思います。どうもありがとう! – Nicolas

2

あなたが言及したように、ここでトリックを適用することができます。

私はこのテストを作成します。

df = pd.DataFrame([[1,2,3], [6,7,8]], columns=[1,2,3]) 
def func(a, b, c): 
    return a + b + c 
df['total'] = df.apply(lambda row: func(row[1], row[2], row[3]), axis='columns') 

出力:

1 2 3 total 
0 1 2 3 6 
1 6 7 8 21 

への私の修正あなたの適用のコードは次のようになります。

df= pd.DataFrame([['A','B','C','D','E','F','1','2001-01-01','1.0']],\ 
    columns = ['Bcat','Brand','Customer','IPC','LOC','MKT_BUD','Type','STARTEFF','Value']) 


df['Priority'] = df.apply(lambda row: priority(row['Bcat'], 
               row['Brand'], 
               row['IPC'], 
               row['Customer'], 
               row['Type']), 
          axis='columns') 

出力:

Bcat Brand Customer IPC LOC MKT_BUD Type STARTEFF  Value Priority 
0 A  B  C   D E F  1 2001-01-01 1.0  15.333333  
+0

@ysearkaソリューションで定義したデータフレームを使用してテストしました。私は何の誤りもなかった。私の場合、len(Bcat)= 1 – Vico

+0

これは、いくつかの行を含むデータフレーム上で動作するように見えるので、実際にはセル内の文字列の長さです。ニースの解決策! – ysearka

+0

これは完全にありがとうございます! – Nicolas

3

これは、すべての行に同時に適用されるベクトル化されたソリューションです。それは、それ自身の各行に関数を適用するよりもはるかに速く実行する必要があります。

def priority(df): 
    df = df.assign(priority=1) 
    df['Type'] = df['Type'].astype(str) 
    mask = df['Bcat'] != '*' 
    df.loc[mask, 'priority'] += df.loc[mask, 'Bcat'].apply(len)/3. 
    df.loc[df['Brand'] != '*', 'priority'] += 2 
    df.loc[df['IPC'] != '*', 'priority'] += 4 
    df.loc[~df['Customer'].isin(['*', 'REPLCUST']), 'priority'] += 8 
    df.loc[df['Type'] == 'Default', 'priority'] -= 16 
    return df 

>>> priority(df) 
    Bcat Brand Customer IPC LOC MKT_BUD Type STARTEFF Value priority 
0 A  B  C D E  F 1 2001-01-01  1 15.333333 
関連する問題