0

I'm trying to write a code to define buildings geometric shape, but I have this error message:

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

I read a lot of posts about it here and somewhere online, but I couldn't find anything similar.

This is my csv_file:

fid Shrt_axis   Lng_axis    angle   area_rett   perimeter   area
1   12.5    26.07   136.31  325.91  77.15   299.28
2   11.01   11.68   105.24  128.66  45.39   125.11

this is my code:

import pandas as pd
Tabella = pd.read_csv("prova_2.csv", sep=";", header= )

lato_corto = Tabella.loc[:,'Shrt_axis']    
lato_lungo = Tabella.loc[:,'Lng_axis']
#continue with other dates from my data set.

rapporto_lati = lato_lungo / lato_corto

for row in Tabella:
    if 1 =< rapporto_lati =< 1.1:
        print("è un quadrato")

Then i read something on internet, but it didn't work correctly:

if (rapporto_lati > 1) & (rapporto_lati < 1.1):
    print('è un quadrato')

In this case, I hadn't any error message, but the result wasn't ok.

9769953
  • 10,344
  • 3
  • 26
  • 37
  • The best duplicate I have found so far is https://stackoverflow.com/questions/38834028/use-a-empty-a-bool-a-item-a-any-or-a-all?rq=1 . Unfortunately, this is flagged itself as a duplicate, but the latter only partially solves the problem (it doesn't handle chained comparisons, while the question linked in this comment does). Hence, I'm loath to mark this question as a duplicate yet. – 9769953 Jul 03 '19 at 10:56
  • The last two lines of code should also yield an error; the same error, in fact. – 9769953 Jul 03 '19 at 11:01
  • Note that if you're stepping through your dataframe row-wise, you should do things differently. But, in fact, you shouldn't be stepping through your dataframe row-wise: you need to operate on the whole table/column/series at once. – 9769953 Jul 03 '19 at 11:03
  • @00 the last two lines of code do not yield an error, because `&` is a valid operation on numpy boolean arrays. At least in my version it looks equivalent to [np.logical_and](https://docs.scipy.org/doc/numpy/reference/generated/numpy.logical_and.html). The condition is then equivalent to something like `if np.array([True, True, False, False,...]):` which always is `True` as long as the array is not empty. – Leporello Jul 03 '19 at 12:18
  • @Leporello For which version of Python and NumPy? If I copy your code, I get a `ValueError`, as above. I'm using Python 3.7.3 with NumPy 1.16.4. Perhaps this has long been a warning, and has been upgraded to an exception. – 9769953 Jul 03 '19 at 13:18
  • Thanks for your kind reply. I use Python 3.6 and NumPy included in this version. I tried to use the & and | instead "and" "or", but how I said in my first post, it doesn't work, i didn't have the result expected. I need to be sure about the code, because this is only an example, but the whole table has 12500 rows. – daniela Jul 03 '19 at 15:46
  • @00 Python 2.7.15 and numpy 1.14.3 here: `np.array([True, True]) & np.array([False, True])` is a valid operation returning `np.array([False, True])` and does not give any warning. FWIW I think making it an error is better design (because of the ambiguities such as that of the OP). – Leporello Jul 03 '19 at 16:01
  • @Leporello Indeed, I wouldn't rely on this behaviour, even if it's possible. While it definitely works for lists (any non-empty list, even `[0]` or `[False]`, evaluates as `True`), NumPy arrays are quite different beasts. – 9769953 Jul 03 '19 at 20:56
  • @Leporello This is odd: I'm running your example with Python 2.7.16 and NumPy 1.14.3 (on MacOS), and I do get a `ValueError` with `if np.array([True, True]) & np.array([False, True]): pass`. Something's fishy here. – 9769953 Jul 03 '19 at 20:58
  • @00 I'm on Windows 10 using an Anaconda distribution (conda 4.6.14). The thing actually makes [bitwise and](https://docs.scipy.org/doc/numpy/reference/generated/numpy.bitwise_and.html?highlight=#numpy.bitwise_and) rather than logical and (tested with the bitwise doc examples). Maybe it is an implementation quirk? – Leporello Jul 04 '19 at 08:42

1 Answers1

1

Use:

if ((rapporto_lati > 1) & (rapporto_lati < 1.1)).all():
    print("è un quadrato")

You can only use the (chained) comparison method if the variable concerns a single item: for multiple items, such as a list, (NumPy) array or Pandas Series, you'll need to ascertain the comparison for every individual element. This is why you need .all() (or .any(), if your intention is that just one item-comparison being valid is enough).

For the chained comparison, you still can't do the following with arrays and such:

(1 <= rapporto_lati < 1.1).all()   # invalid

For NumPy arrays (and thus Pandas Series), you have to perform the comparisons individually, and combine the comparisons. Each comparison yields an array with True or False items, and these two arrays can be combined with the & operator (using standard boolean logic). You will need to wrap the two comparisons in parentheses as well, since the & operators binds tighter than the comparison operators.

With all that, you arrive at the above construction.

9769953
  • 10,344
  • 3
  • 26
  • 37