【问题标题】:Pandas' `to_csv` doesn't behave the same way as printingPandas 的 `to_csv` 的行为方式与打印不同
【发布时间】:2021-01-02 07:55:41
【问题描述】:

考虑以下操作顺序:

  1. 创建一个包含两列的数据框,其类型为int64float64
  2. 通过将所有列转换为object 创建一个新框架
  3. 检查新的数据框
  4. 保留新的数据框
  5. 期望第二列得到持久化,如第三步所示:即作为字符串,而不是作为 float64

如下图所示:

# Step 1
df = pd.DataFrame.from_dict({'a': [3, 2, 1, 0], 'b': [1, 500.43, 256.13, 5]})  

# Step 2
df2 = df.astype(object)

# Step 3
df2.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   a       4 non-null      object
 1   b       4 non-null      object
dtypes: object(2)
memory usage: 192.0+ bytes

# NOTE notice how column `b` is rendered
df2
   a       b
0  3       1
1  2  500.43
2  1  256.13
3  0       5

# Step 4
df2.to_csv("/tmp/df2", index=False,  sep="\t")

现在让我们检查生成的输出:

$ cat df2
a   b
3   1.0
2   500.43
1   256.13
0   5.0

注意列b 是如何保留的:即使数据类型为object,小数位仍然存在于整数中。为什么会这样?我在这里错过了什么?

我将 Pandas 1.1.2 与 Python 3.7.9 一起使用。

【问题讨论】:

  • 将类型更改为对象不会更改数据框中实际存储的内容,它只会更改列的打印方式。
  • 谢谢@cs95。如何将 float64 转换为字符串,以使整数省略零?
  • 有一些方法,但它们并不漂亮。您是要修复单列还是多列?
  • 您可以将 float cols 转换为字符串并去掉小数位:df.select_dtypes('float').astype(str).apply(lambda x: x.str.rstrip('.0'))
  • @cs95 是迂腐的,它确实改变了存储在数据框中的内容。在df 中,您有一个dtype 为numpy.float64 的列,由pandas 包装的原始缓冲区由一个64 位浮点数数组组成。当您执行astype(object) 时,底层缓冲区将转换为 PyObject 指针数组。这些都指向 python float 对象。所以数据确实改变了。

标签: python pandas dataframe


【解决方案1】:

我对 pandas 不是很好,但我还在学习。我查看了一些解决方案,并想为什么不在我们将数据发送到 csv 文件之前对其进行应用。

这是我将值打印为15 而不是1.05.0 的操作

df 中的值是字符串、浮点数、整数的混合

import pandas as pd
df = pd.DataFrame.from_dict({'a': [3, 2, 1, 's', 't'], 'b': [1, 500.43, 256.13, 5, 'txt']})  
df2 = df.astype(object)
def convert(x):
    a = []
    for i in x.to_list():
        a.append(coerce(i))
    return pd.Series(a)
        
    #return pd.Series([str(int(i)) if int(i) == i else i for i in x.to_list()])

def coerce(y):
    try:
        p = float(y)
        q = int(y)
        if p != q:
            return str(p)
        else:
            return str(q)
    except:
        return str(y)

df2.apply(convert).to_csv("abc.txt", index=False, sep="\t")

文件中的输出将是:

a   b
3   1
2   500.43
1   256.13
s   5
t   txt

df 中的所有值都是数字(整数或浮点数)

import pandas as pd
df = pd.DataFrame.from_dict({'a': [3, 2, 1, 0], 'b': [1, 500.43, 256.13, 5]})  
df2 = df.astype(object)
def convert(x):
    return pd.Series([str(int(i)) if int(i) == i else i for i in x.to_list()])
df2.apply(convert).to_csv("abc.txt", index=False, sep="\t")

输出如下:

a   b
3   1
2   500.43
1   256.13
0   5

这里我假设 df2 中的所有值都是数字。如果它有一个字符串值,那么 int(i) 将失败。

【讨论】:

    【解决方案2】:

    我认为,'object' 是 NumPy/pandas dtype,而不是 python 数据类型之一。 如果你运行:

    type(df2.iloc[0,1])
    

    在第 4 步之前,您将获得 'float' 数据类型,即使它已更改为 'object'

    你可以使用:

    df.to_csv("df.csv",float_format='%g', index=False, sep="\t")
    

    而不是在第 2 步中强制转换。

    【讨论】:

    • dtype='str':列b 用于计算,应保持为float。我只需要更改持久化到文件的数据类型。
    • 可以使用df.to_csv("df.csv",float_format='%g', index=False, sep="\t")写入.csv文件
    • 我确实考虑过“%g”。但是,在某些情况下,这可能会导致指数表示法。
    猜你喜欢
    • 2019-04-28
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 1970-01-01
    • 2017-12-13
    相关资源
    最近更新 更多