如果条件与数据框架一起使用

10

如果条件为真,即df[df["tg"] > 10df[df["tg"] < 32,则乘以五,否则除以两。但是,我遇到了以下错误:

ValueError: DataFrame的真值不明确。请使用a.empty、a.bool()、a.item()、a.any()或a.all()。

d = {'year': [2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001],
     'day': [1, 2, 3, 4, 1, 2, 3, 4,],
     'month': [1, 1, 1, 1, 2, 2, 2, 2],
     'tg': [10, 11, 12, 13, 50, 21, -1, 23],
     'rain': [1, 2, 3, 2, 4, 1, 2, 1]}
df = pd.DataFrame(data=d)
print(df)


[OUT]

   year  day  month  tg  rain
0  2001    1      1  10     1
1  2001    2      1  11     2
2  2001    3      1  12     3
3  2001    4      1  13     2
4  2001    1      2  50     4
5  2001    2      2  21     1
6  2001    3      2  -1     2
7  2001    4      2  23     1

df["score"] = (df["tg"] * 5) if ((df[df["tg"] > 10]) and (df[df["tg"] < 32])) else (df["tg"] / 2) 

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

我想要什么

   year  day  month  tg  rain   score
0  2001    1      1  10     1    5
1  2001    2      1  11     2    55
2  2001    3      1  12     3    60
3  2001    4      1  13     2    65
4  2001    1      2  50     4    25
5  2001    2      2  21     1    42
6  2001    3      2  -1     2    0.5
7  2001    4      2  23     1    46


1
你正在寻找 where:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.where.html - foglerit
虽然不是最有效的解决方案,但也值得注意的是使用“map”将标量函数应用于每个元素:df["score"] = df["tg"].map(lambda x: x*5 if 10<x<32 else x/2) - alani
1
你期望的输出在索引5、6和7上似乎是错误的。 - not_speshal
5个回答

5
您可以使用where
df['score'] = (df['tg']*5).where(df['tg'].between(10, 32), df['tg']/5)

2
非常微小,但只是帮助 OP 匹配他们的预期输出。顺便说一下,我也有同样的想法 =D - not_speshal

4

使用np.where

# do you need `inclusive=True`? Expected output says yes, your logic says no
mask = df['tg'].between(10,32, inclusive=False)
df['score'] = df['tg'] * np.where(mask, 5, 1/2)

 # or
 # df['score'] = np.where(mask, df['tg'] * 5, df['tg']/2)

输出:

   year  day  month  tg  rain  score
0  2001    1      1  10     1    5.0
1  2001    2      1  11     2   55.0
2  2001    3      1  12     3   60.0
3  2001    4      1  13     2   65.0
4  2001    1      2  50     4   25.0
5  2001    2      2  21     1  105.0
6  2001    3      2  -1     2   -0.5
7  2001    4      2  23     1  115.0

2

让我们尝试使用for循环来修复它

[x * 5 if (x > 10 and x < 32) else (x / 2) for x in df['tg']]
Out[64]: [5.0, 55, 60, 65, 25.0, 105, -0.5, 115]

2

您可以使用df.loc

mask = (df["tg"] > 10) & (df["tg"] < 32)
df.loc[mask, "score"] = df["tg"] * 5
df.loc[~mask, "score"] = df["tg"] / 2

1
更详细的错误信息解释,请查看pandas文档中的this
除了已经提供的优秀答案,另一个选择是来自pyjanitorcase_when函数,它可能是一个有用的抽象,特别是对于多个条件或者你需要保留Pandas扩展数据类型的情况。
# pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor

df.case_when(
      df.tg.gt(10) & df.tg.le(32), # condition
      df.tg.mul(5), # result if True
      df.tg.div(2), # result if False
      column_name='score')
 
   year  day  month  tg  rain  score
0  2001    1      1  10     1    5.0
1  2001    2      1  11     2   55.0
2  2001    3      1  12     3   60.0
3  2001    4      1  13     2   65.0
4  2001    1      2  50     4   25.0
5  2001    2      2  21     1  105.0
6  2001    3      2  -1     2   -0.5
7  2001    4      2  23     1  115.0

更多例子可以在这里找到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接