10

I want if the conditions are true if df[df["tg"] > 10 and df[df["tg"] < 32 then multiply by five otherwise divide by two. However, I get the following error

ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or 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().

What I want

   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

neuron
  • 1,949
  • 1
  • 15
  • 30
Mr. Hankey
  • 954
  • 1
  • 5
  • 12
  • 1
    You are looking for `where`: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.where.html – foglerit Nov 04 '21 at 16:12
  • Although not the most efficient solution, it is also worth being aware of `map` to apply a scalar function to each element: `df["score"] = df["tg"].map(lambda x: x*5 if 10 – alani Nov 04 '21 at 16:15
  • 1
    Your expected output seems wrong for indices 5, 6 and 7. – not_speshal Nov 04 '21 at 16:19

5 Answers5

5

You can use where:

df['score'] = (df['tg']*5).where(df['tg'].between(10, 32), df['tg']/5)
Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
mozway
  • 194,879
  • 13
  • 39
  • 75
4

Use 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)

Output:

   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
Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
2

Let try to fix it with for loop

[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]
BENY
  • 317,841
  • 20
  • 164
  • 234
2

You can use df.loc

mask = (df["tg"] > 10) & (df["tg"] < 32)
df.loc[mask, "score"] = df["tg"] * 5
df.loc[~mask, "score"] = df["tg"] / 2
simondvt
  • 324
  • 3
  • 13
1

For a more detailed explanation of your error message, have a look at this from the pandas' docs.

Another option, in addition to the already excellent answers, is the case_when function from pyjanitor, which could be a helpful abstraction, especially for multiple conditions, or you probably need to preserve Pandas extension dtypes:

# 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

More examples can be found here

sammywemmy
  • 27,093
  • 4
  • 17
  • 31