web-dev-qa-db-ja.com

pandas applyを使用するとAttributeErrorが発生するのはなぜですか?

条件に基づいてNaN値をカテゴリ値に変換するにはどうすればよいですか。 Nan値を変換しようとするとエラーが発生します。

category           gender     sub-category    title

health&beauty      NaN         makeup         lipbalm

health&beauty      women       makeup         lipstick

NaN                NaN         NaN            lipgloss

私のDataFrameは次のようになります。そして、性別のNaN値をカテゴリー値に変換する私の関数は次のようになります

def impute_gender(cols):
    category=cols[0]
    sub_category=cols[2]
    gender=cols[1]
    title=cols[3]
    if title.str.contains('Lip') and gender.isnull==True:
        return 'women'
df[['category','gender','sub_category','title']].apply(impute_gender,axis=1)

コードを実行するとエラーが発生する

----> 7     if title.str.contains('Lip') and gender.isnull()==True:
      8         print(gender)
      9 

AttributeError: ("'str' object has no attribute 'str'", 'occurred at index category')

完全なデータセット- https://github.com/lakshmipriya04/py-sample

8
LPR

ここで注意すべき点-

  1. 2つの列のみを使用している場合、4列を超えるapplyを呼び出すのは無駄です。
  2. applyの呼び出しは、遅く、ベクトル化のメリットがないため、一般に無駄です。
  3. 適用では、スカラーを扱っているため、.strオブジェクトのようにpd.Seriesアクセサーを使用しません。 title.containsで十分です。または、より厳密に言えば、"lip" in title
  4. gender.isnullは完全に間違っています。genderはスカラーで、isnull属性がありません

オプション1
np.where

m = df.gender.isnull() & df.title.str.contains('lip')
df['gender'] = np.where(m, 'women', df.gender)

df
        category gender sub-category     title
0  health&beauty  women       makeup   lipbalm
1  health&beauty  women       makeup  lipstick
2            NaN  women          NaN  lipgloss

これは高速であるだけでなく、単純でもあります。大文字と小文字の区別が心配な場合は、containsチェックで大文字と小文字を区別しないようにすることができます-

m = df.gender.isnull() & df.title.str.contains('lip', flags=re.IGNORECASE)

オプション2
別の代替手段はpd.Series.mask/pd.Series.whereを使用することです-

df['gender'] = df.gender.mask(m, 'women')

または、

df['gender'] = df.gender.where(~m, 'women')
df
        category gender sub-category     title
0  health&beauty  women       makeup   lipbalm
1  health&beauty  women       makeup  lipstick
2            NaN  women          NaN  lipgloss

maskは、指定されたマスクに基づいて新しい値を列に暗黙的に適用します。

14
cs95

または、単に@COLDSPEEDの回答のオプション3としてlocを使用します

cond = (df['gender'].isnull()) & (df['title'].str.contains('lip'))
df.loc[cond, 'gender'] = 'women'


    category        gender  sub-category    title
0   health&beauty   women   makeup          lipbalm
1   health&beauty   women   makeup          lipstick
2   NaN             women       NaN         lipgloss
7
Vaishali

NaN値が原因である場合、fillnaはメソッドの1つになります:-)

df.gender=df.gender.fillna(df.title.str.contains('lip').replace(True,'women'))
df
Out[63]: 
        category gender sub-category     title
0  health&beauty  women       makeup   lipbalm
1  health&beauty  women       makeup  lipstick
2            NaN  women          NaN  lipgloss
3
YOBEN_S