Pandas DataFrame:无法将字符串转换为float

时间:2016-08-01 20:06:34

标签: python string pandas dataframe valueconverter

我在pandas数据框中有一个Column1列,其类型为str,其值如下:

import pandas as pd
df = pd.read_table("filename.dat")
type(df["Column1"].ix[0])   #outputs 'str'
print(df["Column1"].ix[0])

输出'1/350'。所以,这是一个字符串。我想把它转换成一个浮点数。

我试过了:

df["Column1"] = df["Column1"].astype('float64', raise_on_error = False)

但是这并没有将值改为浮点数。

这也失败了:

df["Column1"] = df["Column1"].convert_objects(convert_numeric=True)

这失败了:

df["Column1"] = df["Column1"].apply(pd.to_numeric, args=('coerce',))

如何转换列的所有值" Column1"进入花车?我可以以某种方式使用正则表达式删除括号吗?

编辑:

该行

df["Meth"] = df["Meth"].apply(eval)

有效,但只有我使用它两次,即

df["Meth"] = df["Meth"].apply(eval)
df["Meth"] = df["Meth"].apply(eval)

为什么会这样?

3 个答案:

答案 0 :(得分:4)

您需要评估表达式(例如'1/350')以获得结果,您可以使用Python的eval()函数。

通过将Panda的apply()函数包裹起来,您可以对列中的每个值执行eval()函数。例如:

df["Column1"].apply(eval)

在您解释文字时,您还可以使用文档中所述的ast.literal_eval函数。更新:这不起作用,因为使用了{{1}仍然仅限于加法和减法(source)。

备注:正如其他答案和对此问题的评论中所提到的,使用literal_eval()并非没有风险,因为您基本上是在执行传入的任何输入。换句话说,如果你的输入包含恶意代码,你给它一个免费通行证。

备选方案:

eval()
不洁数据的情况下

第二个替代

通过使用正则表达式,我们可以删除任何出现resp的非数字。在分子之前和分母之后。

# Define a custom div function
def div(a,b):
    return int(a)/int(b)

# Split each string and pass the values to div
df_floats = df['col1'].apply(lambda x: div(*x.split('/')))

我们会失去一些性能,但好处是,即使使用# Define a custom div function (unchanged) def div(a,b): return int(a)/int(b) # We'll import the re module and define a precompiled pattern import re regex = re.compile('\D*(\d+)/(\d+)\D*') df_floats = df['col1'].apply(lambda x: div(*regex.findall(x)[0])) 之类的输入,我们仍然会得到'!erefdfs?^dfsdf1/350dqsd qsd qs d'的值。

<强>性能:

对具有100.000行的数据帧上的两个选项进行计时时,第二个选项(使用用户定义的1/350函数)明显获胜:

  • 使用div:1循环,最好3:每循环1.41秒
  • 使用eval:10个循环,最好是每个循环3:159毫秒
  • 使用div:1循环,最好是每循环3:275 ms

答案 1 :(得分:3)

我讨厌提倡使用eval。我不想花时间在这个答案上,但我被迫,因为我不想让你使用eval

所以我写了这个函数,它适用于pd.Series

def do_math_in_string(s):
    op_map = {'/': '__div__', '*': '__mul__', '+': '__add__', '-': '__sub__'}
    df = s.str.extract(r'(\d+)(\D+)(\d+)', expand=True)
    df = df.stack().str.strip().unstack()
    df.iloc[:, 0] = pd.to_numeric(df.iloc[:, 0]).astype(float)
    df.iloc[:, 2] = pd.to_numeric(df.iloc[:, 2]).astype(float)
    def do_op(x):
        return getattr(x[0], op_map[x[1]])(x[2])
    return df.T.apply(do_op)

示范

s = pd.Series(['1/2', '3/4', '4/5'])

do_math_in_string(s)

0    0.50
1    0.75
2    0.80
dtype: float64
do_math_in_string(pd.Series(['1/2', '3/4', '4/5', '6+5', '11-7', '9*10']))

0     0.50
1     0.75
2     0.80
3    11.00
4     4.00
5    90.00
dtype: float64

请不要使用eval

答案 2 :(得分:2)

您可以将eval应用于列:

data = {'one':['1/20', '2/30']}
df = pd.DataFrame(data)

In [8]: df['one'].apply(eval)
Out[8]:
0    0.050000
1    0.066667
Name: one, dtype: float64