Pandas read_csv dtype 读取所有列,但很少作为字符串

问题描述 投票:0回答:5

我正在使用 Pandas 读取一堆 CSV。将选项 json 传递给 dtype 参数来告诉 pandas 将哪些列读取为字符串而不是默认值:

dtype_dic= { 'service_id':str, 'end_date':str, ... }
feedArray = pd.read_csv(feedfile , dtype = dtype_dic)

在我的场景中,所有除了少数特定列之外的列都将被读取为字符串。因此,我不想将

dtype_dic
中的几列定义为 str,而是将我选择的几列设置为 int 或 float。有办法做到吗?

这是一个循环遍历具有不同列的各种 CSV 的循环,因此在将整个 csv 读取为字符串(

dtype=str
)后进行直接列转换并不容易,因为我不会立即知道 csv 具有哪些列。 (我宁愿花精力来定义 dtype json 中的所有列!)

编辑:但是,如果有一种方法可以处理要转换为数字的列名称列表,而不会在该 csv 中不存在该列时出错,那么,如果没有其他方法,那么这将是一个有效的解决方案在 csv 读取阶段本身执行此操作。

注意:这听起来像以前问过的问题,但那里的答案走了一条非常不同的路径(布尔相关),这不适用于这个问题。请不要标记为重复!

python pandas csv
5个回答
168
投票

对于 Pandas 1.5.0+,有一个简单的方法可以做到这一点。如果您使用

defaultdict
而不是普通的
dict
作为
dtype
参数,则字典中未明确列出的任何列都将使用默认值作为其类型。例如

from collections import defaultdict
types = defaultdict(str, A="int", B="float")
df = pd.read_csv("/path/to/file.csv", dtype=types, keep_default_na=False)

(我还没有测试过,但我想你仍然需要

keep_default_na=False


对于旧版本的 Pandas:

您可以将整个 csv 作为字符串读取,然后将所需的列转换为其他类型,如下所示:

df = pd.read_csv('/path/to/file.csv', dtype=str, keep_default_na=False)
# example df; yours will be from pd.read_csv() above
df = pd.DataFrame({'A': ['1', '3', '5'], 'B': ['2', '4', '6'], 'C': ['x', 'y', 'z']})
types_dict = {'A': int, 'B': float}
for col, col_type in types_dict.items():
    df[col] = df[col].astype(col_type)
如果某些列是空字符串或类似于

keep_default_na=False

 的内容,那么 
NA
是必要的,默认情况下,pandas 将其转换为
NA
类型的
float
,这将使您最终得到
str
/ 的混合数据类型
float

另一种方法,如果您确实想在读入文件时为所有列指定正确的类型并且之后不更改它们:仅读入列名(无行),然后使用它们来填充哪些列应该是字符串

col_names = pd.read_csv('file.csv', nrows=0).columns
types_dict = {'A': int, 'B': float}
types_dict.update({col: str for col in col_names if col not in types_dict})
pd.read_csv('file.csv', dtype=types_dict)

47
投票

我最近遇到了同样的问题,虽然我只有一个 csv 文件,所以我不需要循环文件。我认为这个解决方案也可以适应循环。

这里我介绍一个我用过的解决方案。 Pandas 的

read_csv
有一个名为
converters
的参数,它会覆盖
dtype
,因此您可以利用此功能。

示例代码如下: 假设我们的

data.csv
文件包含除
A
B
(字符串列)之外的所有 float64 列。您可以使用以下方式阅读此文件:

df = pd.read_csv('data.csv', dtype = 'float64', converters = {'A': str, 'B': str})  

代码给出警告,转换器会覆盖这两列 A 和 B 的数据类型,结果如预期。

关于循环多个 csv 文件,我们需要做的就是找出哪些列是例外,需要放入转换器中。如果文件具有相似的列名模式,这很容易,否则会变得乏味。


7
投票

您可以执行以下操作:

pd.read_csv(self._LOCAL_FILE_PATH,
            index_col=0,
             encoding="utf-8",
             dtype={
                    'customer_id': 'int32',
                    'product_id': 'int32',
                    'subcategory_id': 'int16',
                    'category_id': 'int16',
                    'gender': 'int8',
                    'views': 'int8',
                    'purchased': 'int8',
                    'added': 'int8',
                    'time_on_page': 'float16',
                 })

3
投票

使用转换器扩展@MECoskun的答案,并同时剥离前导和尾随空格,使转换器更加通用:

df = pd.read_csv('data.csv', dtype = 'float64', converters = {'A': str.strip, 'B': str.strip}) 

如果需要,还可以使用 lstrip 和 rstrip 来代替 strip。注意,不要使用 strip(),而只是使用 strip。当然,您不会剥离非字符串。


2
投票

已接受的答案已于 2023 年 2 月 7 日更新,以介绍 defauldict

 参数的 
dtype
 功能。然而这个答案行不通。

from collections import defaultdict types = defaultdict(str, A="int", B="float") df = pd.read_csv("/path/to/file.csv", dtype=types, keep_default_na=False) ... TypeError: data type '' not understood
确实,

defaultdict

的第一个参数是可调用的,用于创建默认条目,因此:

>>> (str)() ''
但是 

''

 不是有效类型,不像:

>>> (lambda:str)() str
所以正确答案应该是:

from collections import defaultdict types = defaultdict(lambda: str, A="int", B="float") df = pd.read_csv("/path/to/file.csv", dtype=types, keep_default_na=False)
示例:

>>> df A B C D 0 1 2.0 hello world 1 3 4.0 hello world >>> df.dtypes A int64 B float64 C object D object dtype:object

编辑:根据@DaniilFajnberg的建议,您还可以使用lambda: 'string'

将Pandas dtypes用作字符串:

>>> df.dtypes A int64 B float64 C string[python] D string[python] dtype: object
    
© www.soinside.com 2019 - 2024. All rights reserved.