【问题标题】:How to setup string to float converters for numpy genfromtxt如何为 numpy genfromtxt 设置字符串到浮点转换器
【发布时间】:2016-01-18 21:28:29
【问题描述】:

我找到了许多方法来输入带有文本条目的 csv 文件作为 Python 中的数字数组,例如 thisthis,但没有一种方法适合我,也没有一种方法适合我。我也无法在 the manual 中找到 numpy 或其他常用工具的答案,但也许它就在那里,我就是无法理解。

我在 csv 中有这样的数据:

"experiment 1"
"var1","var2","var3","var4","var5"
"7","0","1","3","1"
"8","4","3","1","1"
"8","5","3","3","1"
"8","6","3","3","3"

我尝试使用

读取数据
dataArray = np.genfromtxt('Input Data/'+fileName,delimiter=',',skiprows=2)

我也尝试添加

.astype(np.float)

到最后。但无论哪种情况,我最终得到的是:

[[ nan  nan  nan  nan  nan]
[ nan  nan  nan  nan  nan]
[ nan  nan  nan  nan  nan]
[ nan  nan  nan  nan  nan]]

因为根据文档将数字列中的字符串转换为 nan 是 genfromtxt 应该做的。 genfromtxt 也有一个 converters 参数,但我能找到的使用它的唯一示例来自文档:

converters = {3: lambda s: float(s or 0)}

我真的无法理解这种语法。假设内置转换器可以处理我的数据,那么为此编写转换器参数的正确语法是什么?如果转换器不能满足我的需求,有人知道如何读取这些数据吗?我原以为这会非常简单,我会在 5 分钟内找到,但我现在已经浪费了好几个小时了。

【问题讨论】:

  • 也许,你应该考虑重命名你的问题,因为我认为它更多的是关于如何将你的数据文件读取到一个 numpy 数组,对吧?浮点转换器似乎只是一种可能性。

标签: python arrays csv numpy


【解决方案1】:

我找到了两个解决方案。 1. 使用转换器 2. 使用excel或LibreCalc。

  1. 转换器对我有用,但它们使用字典,因此您必须指定每一列。当它们是字符串时,对于保留特定列很有用,但除此之外不是一个很好的解决方案。
    import numpy as np;

myConverters = {}
myConverters[0] = lambda s:float(s.decode('ascii').strip('"')); #column zero is a number
myConverters[1] = lambda s:s; #column 1 is a string

filename = 'Spread of Disease population-density-table.csv';

data = np.genfromtxt(filename, skip_header= 6, #skip_footer=10, 
                     delimiter= ",", 
                     #names= True,
                     #dtype= str,
                     converters = myConverters,

                     )
print(data)

  1. 更简单的解决方案是在 LibreCalc (excel) 中打开文件并另存为 .csv。这会将文件保存为标准(无“)格式。

此后一切照旧。

【讨论】:

    【解决方案2】:

    当你说:

    转换器 = {3: lambda s: float(s or 0)} 我真的无法理解这种语法

    来自Numpy 文档:

    转换器:字典,可选 将列号映射到将该列转换为浮点数的函数的字典。例如,如果第 0 列是日期字符串:converters = {0: datestr2num}。转换器也可用于为缺失数据提供默认值(另请参阅 genfromtxt):转换器 = {3: lambda s: float(s.strip() or 0)}。默认值:无

    所以在例子中:

    转换器 = {3: lambda s: float(s or 0)}

    这意味着converters是一个python字典(python中字典的字面量是{key: value],例子

    dict_example = {1: "the position is 1"}
    

    其中key为1,value为“位置为1”。

    Converters 是一个字典,其中键是文件中列的编号,值是将应用于该列的每个元素的转换。函数在 Python 中也用 lambda 表示(从技术上讲,它们是匿名函数,请在别处查找文档)

    所以

    转换器 = {3: lambda s: float(s or 0)}

    将转换器定义为字典,其中键引用第 3 列,然后将函数 float 应用于该列的每个元素。

    另一个技巧是 float 函数,其中包含 or。这里我们使用的是 or 运算符的shortcircuit

    如果 s 为 null,或者不是数字(请参阅更多详细信息 here),for or 会导致 false,而 false 会导致 0,结果为 0。所以它是一种将任何不是数字(甚至缺失)的东西转换为 0 的简洁形式。如果 s 是一个字符串,或者短路并返回 s

    【讨论】:

      【解决方案3】:

      使用列名读取数据

      要使用np.genfromtext,你应该首先将文件读入一个字符串,删除所有"字符,然后使用cStringIO读取这个字符串:

      >>>import cStringIO
      >>>with open ("123", "r") as myfile:
             data=myfile.read().replace('"', '')
      >>>np.genfromtxt(cStringIO.StringIO(data), skip_header=1, delimiter=",", names = True)
      
      array([(7.0, 0.0, 1.0, 3.0, 1.0),
             (8.0, 4.0, 3.0, 1.0, 1.0),
             (8.0, 5.0, 3.0, 3.0, 1.0),
             (8.0, 6.0, 3.0, 3.0, 3.0)], 
            dtype=[('var1', '<f8'), ('var2', '<f8'), ('var3', '<f8'), ('var4', '<f8'), ('var5', '<f8')]) 
      

      你也可以使用pandas:

      >>>pd.read_csv(file, header=0, skiprows = 1).as_matrix()
      
         var1  var2  var3  var4  var5
      0     7     0     1     3     1
      1     8     4     3     1     1
      2     8     5     3     3     1
      3     8     6     3     3     3
      

      在没有列名的情况下读取数据

      您可以先将文件读取到包含字符串的数组中:

      a = np.genfromtxt('filename', skip_header=2, delimiter=",", dtype = 'str')
      print a
      

      给出:

      [['"7"' '"0"' '"1"' '"3"' '"1"']
       ['"8"' '"4"' '"3"' '"1"' '"1"']
       ['"8"' '"5"' '"3"' '"3"' '"1"']
       ['"8"' '"6"' '"3"' '"3"' '"3"']]
      

      然后使用 numpy 将其转换为浮点数,如下所示:

      a = np.char.strip(a, '"').astype(float)
      print a
      

      给了

      [[ 7.  0.  1.  3.  1.]
       [ 8.  4.  3.  1.  1.]
       [ 8.  5.  3.  3.  1.]
       [ 8.  6.  3.  3.  3.]]
      

      您还建议使用 pandas。要在 pandas DataFrame 中读取它,您可以这样做:

      import pandas as pd
      a = pd.read_csv('./test', header=None, skiprows = 2)
      print a
      

      给出:

         0  1  2  3  4
      0  7  0  1  3  1
      1  8  4  3  1  1
      2  8  5  3  3  1
      3  8  6  3  3  3
      

      【讨论】:

      • 好的,这很接近,并且比每列转换器更易于使用。实际操作如下:dataArray = np.char.strip(np.genfromtxt('Input Data/'+fileName, skip_header=2, delimiter=",", dtype = None), '"').astype(float) 结合了您拥有的两条线并更改了一些不太正确的部分。唯一可能的原因是它也不能处理标题:即使我重新插入, deletechars='"', dtype = 'str',也可以将skip_header=1, names=True, 替换为TypeError: string operation on non-string array。我现在要避免使用熊猫。
      • 好的,不知道你也想看名字。我认为您不能使用 genfromtxt 执行此操作,因为您的文件对于列名和数据条目有不同的分隔符。您可以使用 pandas.read_csv 来做到这一点,因为您可以通过正则表达式指定多个分隔符。
      • 啊,真实数据有匹配的标题——每列的变量名。我已经更新了问题以反映这一点。这应该是一件相当正常的事情,所以我希望genfromtxt 能够为一个知道它是如何工作的人处理它。 deletechars='"' 实际上应该解决这个问题,但它似乎没有做任何事情。也许最好的办法是将csv作为一个txt块打开并删除",然后运行genfromtxt
      • 我同意。我相应地更新了答案。顺便说一句:pandas 真的很简单,也许你应该看看。
      【解决方案4】:

      经过更多的搜索、尝试和斗争,我设法找到了一种方法来做到这一点。

      首先,为了方便,我单独做一个转换公式,在genfromtxt命令中调用:

      convert = lambda x: float(x.strip('"') or -999)
      

      lambda function 所做的是从每个条目中去除双引号字符(或者如果它为空或 nan 将其设置为 -999),然后将条目转换为浮点数。然后它像这样进入genfromtext 命令:

      dataArray = np.genfromtxt('Input Data/'+fileName,delimiter=',',skip_header=2,converters={0: convert,1: convert,2: convert,3: convert,4: convert},dtype=None)
      

      这适用于这种特殊情况,但它有两个问题:(1) 你必须为每一列分别指定转换器——我找不到指定“应用于所有列”的方法。 更好的方法是使用遍历所有列并将转换应用于所有列的迭代函数......然后该函数将指定将其应用于哪些列。如果可能的话,我不知道该怎么做。问题(2)是无法结合转换器读入标头。例如:

      dataArray = np.genfromtxt('Input Data/'+fileName,delimiter=',',skip_header=1,names=True,converters={0: convert,1: convert,2: convert,3: convert,4: convert},dtype=None)  
      

      如果数据上方的行具有列标题,则应该可以工作,但是当从列中读取名称时,它不再是数组,而是元组列表。这可能是因为数据中的列名也有引号,并且转换器没有应用于它们。这无关紧要,因为它们不是数组的一部分,数组都是数字,但这似乎是genfromtxt 的工作方式。也就是说,它似乎不是执行此任务的一个非常好的/稳健的方法,当然它的文档记录很差,因此不清楚它可以做什么或不能做什么以及如何获得做这些事情的方法.

      我对将来遇到此问题的人的建议是寻找一种不同的方法来执行此功能。很多人推荐pandas 用于其他问题中的类似任务,但我不知道它是否更适合这种情况。目前这对我有用,但在不久的将来,它必须被更强大的 csv 阅读器取代,以生成 numpy 可以轻松构建到数组中的文件格式。

      【讨论】:

        【解决方案5】:
        this will print you first two columns in the file
        Since you have two headers you need to skip first to rows with next()
        
        with open("data.csv", 'r') as f:
                r = csv.reader(f, delimiter=',')
                next(r, None)  # skip the header
                next(r, None)  # skip the header
                for row in r:
                    print(row[0],row[1])
        
        7 0
        8 4
        8 5
        8 6
        

        【讨论】:

        • 我相信参数skiprows=2 应该可以处理这个问题。
        • @AaronBramson 你的意思是 np?这是普通的 csv 阅读器,它没有 skiprows 参数,我刚刚搜索了 csv 模块帮助。至少在 python 3.5 中没有跳过 ...
        • 是的,最后它需要是一个numpy数组,所以看起来最好的办法应该是使用numpy的内置方法来做到这一点。 genfromtxt 应该是正确的……如果我能弄清楚转换器的话。另一种选择是在读取之前从 csv 文件中删除引号,但使用转换器应该更通用,因此是首选。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-31
        • 2014-12-24
        • 2021-05-09
        • 2011-07-18
        • 1970-01-01
        相关资源
        最近更新 更多