簡體   English   中英

Pandas - 在方法鏈中使用賦值和 if-else 語句

[英]Pandas - using assign and if-else statement in method chaining

我來自 R 背景,我正在嘗試從 Pandas 中的 dplyr 復制mutate()函數。

我有一個看起來像這樣的數據框:

data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'], 
        'age': [42, 52, 36, 24, 73], 
        'preTestScore': [4, 24, 31, 2, 3],
        'postTestScore': [25, 94, 57, 62, 70]}
df = pd.DataFrame(data, columns = ['name', 'age', 'preTestScore', 'postTestScore'])

我現在嘗試使用assign方法創建一個名為age_bracket的新列,如下所示:

(df.
    assign(age_bracket= lambda x: "under 25" if x['age'] < 25 else
        ("25-34" if x['age'] < 35 else "35+"))

這引發了我無法理解的以下錯誤:

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

我對以下解決方案不感興趣:

df['age_bracket'] = np.where(df.age < 25, 'under 25',
     (np.where(df.age < 35, "25-34", "35+")))

因為我不希望底層 df 改變。 我試圖在方法鏈方面做得更好,我可以在不改變底層 df 的情況下以不同的方式快速探索我的 df。

有什么建議?

可能(但不建議)是因為循環(在apply函數的作用下):

df = (df.
    assign(age_bracket= lambda x: x['age'].apply(lambda y: "under 25" if y < 25 else
        ("25-34" if y < 35 else "35+"))))
print (df)
    name  age  preTestScore  postTestScore age_bracket
0  Jason   42             4             25         35+
1  Molly   52            24             94         35+
2   Tina   36            31             57         35+
3   Jake   24             2             62    under 25
4    Amy   73             3             70         35+

或者numpy.select

df = df.assign(age_bracket= np.select([df.age < 25,df.age < 35], ['under 25', "25-34"], "35+"))

但更好的是使用cut在這里:

df = (df.assign(age_bracket= lambda x: pd.cut(x['age'], 
                                              bins=[0, 25, 35, 150],
                                              labels=["under 25", "25-34", "35+"])))

為什么不將分配與np.where一起使用?

df.assign(age_bracket = np.where(df.age < 25, 'under 25',
     (np.where(df.age < 35, "25-34", "35+"))))

您將獲得帶有新列的原始數據框的副本。

但是我同意@jezrael pd.cut更好。

輸出:

    name  age  preTestScore  postTestScore age_bracket
0  Jason   42             4             25         35+
1  Molly   52            24             94         35+
2   Tina   36            31             57         35+
3   Jake   24             2             62    under 25
4    Amy   73             3             70         35+

使用datar輕松地在 Python 中使用與在 R 中相同的語法:

>>> from datar.all import f, tibble, mutate, if_else
>>> 
>>> data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'], 
...         'age': [42, 52, 36, 24, 73], 
...         'preTestScore': [4, 24, 31, 2, 3],
...         'postTestScore': [25, 94, 57, 62, 70]}
>>> 
>>> df = tibble(**data)
>>> df >> mutate(age_bracket=if_else(
...   f.age < 25, 
...   "under 25",
...   if_else(f.age < 35, "25-34", "35+")
... ))
      name     age  preTestScore  postTestScore age_bracket
  <object> <int64>       <int64>        <int64>    <object>
0    Jason      42             4             25         35+
1    Molly      52            24             94         35+
2     Tina      36            31             57         35+
3     Jake      24             2             62    under 25
4      Amy      73             3             70         35+

免責聲明:我是datar包的作者。

pyjanitorcase_when implementaton在dev這可能是在這種情況下有幫助的,實現想法的靈感來自if_elsepydatatablefcase R中的data.table ; 在引擎蓋下,它使用pd.Series.mask

# pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor as jn

df.case_when(
   df.age.lt(25), 'under 25',  # 1st condition, result
   df.age.lt(35), '25-34',    # 2nd condition, result
   '35+',                     # default
   column_name = 'age_bracket')

    name  age  preTestScore  postTestScore age_bracket
0  Jason   42             4             25         35+
1  Molly   52            24             94         35+
2   Tina   36            31             57         35+
3   Jake   24             2             62    under 25
4    Amy   73             3             70         35+

不過,對於這個用例,由於您是按類別進行分區, pd.cut解決方案更有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM