1

I understand that math.modf returns a string because it is a wrapper around C language standard but it means I am getting the error TypeError: cannot convert the series to <class 'float'> when I try to add the float number as a column to my dataframe. Here is my code:

dataset = pd.read_csv('scandi_short.csv', error_bad_lines=False, 
                  names=['Bloomberg Code', 'index', 'Bid Price', 'Ask Price', 'Trade Price','Bid Volume','Ask Volume','Trade Volume','Update type','Change to Ask','Date','Time in seconds past midnight','Opening price','Condition codes','na','na2'])
dataset['Trade price float'] = int(math.modf(dataset['Trade Price']))
print(dataset)

As you can see I have tried making the math.modf function an integer but I still get the same error, please help!

smci
  • 32,567
  • 20
  • 113
  • 146
John Sonnino
  • 509
  • 5
  • 10
  • You need to apply the math.modf in a per element basis, to the series, use apply – Dani Mesejo Dec 15 '20 at 12:32
  • Use `df.apply` which is same as `map` used on a DataFrame – JenilDave Dec 15 '20 at 12:42
  • brilliant this works. now can you help me to get rid of the whole so I only keep the fraction? I am using `dataset['Trade price float'] = dataset['Trade Price'].apply(math.modf)` but I dont want (0.4000000000000057, 123.0) I just want the first part – John Sonnino Dec 15 '20 at 12:43
  • The [`math.modf`](https://docs.python.org/3/library/math.html?highlight=math.modf#math.modf) doc clearly says **it returns a tuple of two signed floats `(fractional_part, integer_part)`**. Not a string. And if you only want the integer part, you could slice [0], but really you don't even need `modf`, you can just do .`astype(int)` – smci Feb 13 '22 at 01:09
  • Related, near-duplicate: [Pandas get decimal fractional number part from float in a dataframe](https://stackoverflow.com/questions/51638367/pandas-get-decimal-fractional-number-part-from-float-in-a-dataframe) – smci Feb 13 '22 at 01:12
  • One-line answer: a) **don't use `math.modf` on a dataframe, use `np.modf`, it's vectorized**. b) But in your case, `int(modf(df['Price']))` is **just an obfuscation for `df['Price'].astype(int)`**. (If you did use `modf()`, you'd only slice `[0]` to get the integer part and throw away the fractional part, anyway.) – smci Feb 16 '22 at 23:20

1 Answers1

2

The error: TypeError: cannot convert the series to <class 'float'> is because you are passing a Series to math.modf, so you need to either...

a) apply() the function to each element of the Series:

import math
import numpy as np
import pandas as pd

s = pd.Series([1.5, 2.3, 4.0])

res = s.apply(math.modf)
print(res)

Output

0                   (0.5, 1.0)
1    (0.2999999999999998, 2.0)
2                   (0.0, 4.0)
dtype: object

or:

b) better use numpy.modf, which is vectorized:

import math
import numpy as np
import pandas as pd

s = pd.Series([1.5, 2.3, 4.0])

res_np = pd.Series(zip(*np.modf(s)))
print(res_np)

Output

0                   (0.5, 1.0)
1    (0.2999999999999998, 2.0)
2                   (0.0, 4.0)
dtype: object

c) UPDATE: If you only need the first (integer) part, you can do:

res = s.apply(lambda x: math.modf(x)[0])
print(res)

res_np, _ = np.modf(s)
print(res_np)
smci
  • 32,567
  • 20
  • 113
  • 146
Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
  • I am getting `TypeError: 'builtin_function_or_method' object is not subscriptable` – John Sonnino Dec 15 '20 at 12:50
  • @JohnSonnino I just tested the code, make sure you copied correctly – Dani Mesejo Dec 15 '20 at 12:52
  • so sorry but I am getting this error `ValueError: cannot reindex from a duplicate axis` when I try to take the first item – John Sonnino Dec 15 '20 at 13:00
  • what do need to do to this? `dataset['Trade price float'] = dataset['Trade Price'].apply(math.modf)[0]` it doesnt seem to like the index at the end – John Sonnino Dec 15 '20 at 13:01
  • 1
    @JohnSonnino Use the numpy version is faster and easier to use, otherwise, you need to do `dataset['Trade price float'] = dataset['Trade Price'].apply(lambda x: math.modf(x)[0])` – Dani Mesejo Dec 15 '20 at 13:03