从 CSV 确定数据类型 - Python

Posted

技术标签:

【中文标题】从 CSV 确定数据类型 - Python【英文标题】:Determine data type from CSV - Python 【发布时间】:2018-04-14 19:11:01 【问题描述】:

我是 Python 新手,在使用列表时遇到问题。

我暴露了我的问题,如您所见,我有一个具有以下结构的 datos.csv 文件。

1,4.0,?,?,none,?
2,2.0,3.0,?,none,?
2,2.5,2.5,?,tc,39

使用此功能,我将数据存储在列表中。

def main():
    lista = []
    with open('datos.csv','r') as f:
        for line in f:
           lista.append(line.strip().split(','))
    determinar_tipo(lista)

if __name__ == '__main__':
    main()

到目前为止,我没有问题。 但是,当我必须确定元素的类型时,问题就来了。

使用此代码,我可以按列组织我的列表

for columna in itertools.izip(*lista):

此代码允许我将数据视为列,如所示,这是我从这个“for”中收到的示例:

  '1','2','2'
'4.0','2.0','2.5'
        .
        .
        .

如您所见,我的 csv 文件中的数据相同,但按列结构。

好的,这是我的问题。

我必须根据它们的参数来确定每一列的类型,即假设第一列'1', '2', '3',检查第一个元素并且那个元素是该列的类型,在这种情况下,该列的类型为 int。

另一个 '4.0', '2', '2.5' 的例子,我检查主元素的类型并确定它是浮点数。

对于 '?', '?' 的情况, '?' 类型将是“不确定的”。

但是,问题在于符号“?”,如果我得到这些符号,我必须检查列的下一个元素,它会是名为“单词”的元素,'?',' Word', '5',所以列的类型应该是字符串。

这是我为验证它而开发的代码,但我没有正确确定类型。

def determinar_tipo(lista):
  b = 0
  aux = []

  for columna in itertools.izip(*lista):
    if columna[0] != "?":   #If it's a number or string I save it
      aux.append(columna[0])
      print columna[0]
    else:                    #If it's '?'
      if len(columna) > b:
        b = b + 1
        if columna[b] != "?":
          aux.append(columna[b])
          b = 0
        else:
          b = b + 1
          print b
  #Correct code   
  for x in aux:
    try:
      var_type = type(int(x))
    except ValueError:
      try:
        var_type = type(float(x))
      except ValueError:
        var_type = type(x)
    print var_type

代码的第一部分负责将元素存储在另一个列表中以确定每个列的类型,而代码的第二部分负责检查前一个列表中每个元素的类型.

总而言之,我不知道如何让“for”返回正确的元素以正确检查列的类型。

这是我的数据的正确答案:

1  ,  4.0  ,   ?    ,      ?         ,   none   ,   ?
2  ,  2.0  ,  3.0   ,      ?         ,   none   ,   ?
2  ,  2.5  ,  2.5   ,      ?         ,    tc    ,   39
int  float   float     undetermined       string     int**

【问题讨论】:

1、2、2 是 int 有什么原因吗?它可能是一个恰好是 int 的类别,不是吗(考虑到不同值的数量)?还是只有字符串才能成为类别... 如果它是一个没有小数的数字,它将是'int',如果你有小数,它将是'float',如果它是像'none'这样的任何单词,它将是'string ' 键入,如果仅在整个列中 '?'我们必须指出它是“不确定”类型 尝试从一组值中确定类型非常困难,因为您可能需要考虑数千种情况。例如,如果一列是(2, 3.5, 4),它应该是float?那么我需要检查每列中的每个元素吗?我建议在标题行中包含类型信息,然后根据它解析信息。 不不,这更容易,在您公开检查第一个元素的情况下,您确定类型将仅为 int,因此您会将其余值视为 int ,那个案例我也相信如果我没记错的话是不会被评估的 是的,但正如@Adirio 所说,如果它是混合的...(2, 3.5, 4) 一切都可以是有效的float,但如果你将它们视为ints 那么你会怎么做3.5? 【参考方案1】:

我采用了这种方法。重要的部分是发电机。如果有帮助,请告诉我:

import itertools

lista =[
    ['1','4.0','?','?','none','?'],
    ['2','2.0','3.0','?','none','?'],
    ['2','2.5','2.5','?','tc','39']
]
def columnType(column):
    for val in column:
        if val != '?':
            try:
                float(val)
                if '.' in val: yield 'float'
                else: yield 'int'
            except ValueError:
                yield 'string'

for columna in itertools.izip(*lista):
    print columna, next(columnType(columna),'undetermined')

因此而给予:

('1', '2', '2') int
('4.0', '2.0', '2.5') float
('?', '3.0', '2.5') float
('?', '?', '?') undetermined
('none', 'none', 'tc') string
('?', '?', '39') int

编辑:@MaartenFabré 建议的替代功能:

import itertools

lista =[
    ['1','4.0','?','?','none','?'],
    ['2','2.0','3.0','?','none','?'],
    ['2','2.5','2.5','?','tc','39']
]

def columnType(column):
    for val in column:
        if val != '?':
            try:
                float(val)
                if '.' in val: return 'float'
                else: return 'int'
            except ValueError:
                return 'string'
    return 'undetermined'


for columna in itertools.izip(*lista):
    print columna, columnType(columna)

【讨论】:

如果你只使用columnType中的1个值,为什么要使用yield 正确,完美,谢谢队友。很有帮助! @MaartenFabré 我希望它迭代直到第一次有效出现。通过使用生成器,我可以做到这一点。 next(columnType(columna),'undetermined') 给了我columnType(columna) 的第一个有效出现,如果找不到它,它会给我回退'undetermined' 在方法的末尾添加一个return 'undefined'达到同样的效果【参考方案2】:

我更改了函数的名称以便它们更有意义:

def determinar_tipo(valor):
    if valor == '?':
        return 'undetermined'
    try:
        int(valor)
    except ValueError:
        pass
    else:
        return int
    try:
        float(valor)
    except ValueError:
        return str
    else:
        return float

def determinar_tipos(lista):
    aux = []
    for columna in itertools.izip(*lista):
        i = 0
        while i < len(columna) and columna[i] == '?':
            i += 1
        aux.append(columna[i])
    for i, each in enumerate(aux):
        aux[i] = determinar_tipo(each)
    return aux

【讨论】:

以上是关于从 CSV 确定数据类型 - Python的主要内容,如果未能解决你的问题,请参考以下文章

根据 CSV 文件行中的值确定数据类型

python中CSV数据的数据类型识别/猜测

Python:从 CSV 读取数据类型 LineString

在python中将具有不同数据类型的pandas数据框导出到csv

在 python 中使用 csv.DictReader 进行数据类型转换的最快方法

无法在python数据框中将列类型从对象转换为str