【问题标题】:how to convert string array of mixed data types如何转换混合数据类型的字符串数组
【发布时间】:2017-01-17 09:46:26
【问题描述】:

假设我已经读取一个文件并将其加载到一个混合数据的二维矩阵中(下面提供了一个示例)

# an example row of the matrix
['529997' '46623448' '2122110124' '2310' '2054' '2' '66' '' '2010/11/03-12:42:08' '26' 'CLEARING' '781' '30' '3' '0' '0' '1']

我想将这块数据转换成他们的数据类型,以便能够使用 numpy 和 scipy 对其进行统计分析。

所有列的数据类型都是整数除了第 8 个索引是 DateTime,第 10 个索引是纯字符串。

问题:

这种对话最简单的方法是什么?


编辑

性能比可读性更重要,我要转换4.5m行数据然后再处理!

【问题讨论】:

  • 到目前为止你有没有尝试过?那么空字符串呢?
  • @Kasramvd 那些是 N/A 整数,0 或 -1 将被替换为空值。正如我所说的The datatype for all of the columns is integer except the 8th index this is DateTime and the 10th index is pure string.
  • 您在第 7 个索引中有一个空字符串(尽管您的项目没有用逗号分隔!)所以您想将该空字符串更改为什么?
  • @Kasramvd 显示的行是print mtx[0] 的结果!它已经被加载,不需要, 分隔符! so you want to change that empty string to what?: 到 0。
  • 你是如何加载这个的?你试过np.genfromtxtdtype=None 吗?接下来你会做什么样的处理?

标签: python arrays numpy converter mixed


【解决方案1】:

这是一个线性列表理解:

In [24]: from datetime import datetime
In [25]: func = lambda x: datetime.strptime(x, "%Y/%m/%d-%H:%M:%S")
In [26]: [{8:func, 10:str}.get(ind)(item) if ind in {8, 10} else int(item or '0') for ind, item in enumerate(lst)]
Out[26]: 
[529997,
 46623448,
 2122110124,
 2310,
 2054,
 2,
 66,
 0,
 datetime.datetime(2010, 11, 3, 12, 42, 8),
 26,
 'CLEARING',
 781,
 30,
 3,
 0,
 0,
 1]

【讨论】:

  • 我知道我可以用for 来转换我的1m-row 矩阵。只是想知道,有没有什么方法可以扩展这个解决方案来转换整个矩阵?顺便说一句,很好的解决方案。 +1
  • @Dariush 我不建议对所有问题都使用这种方法,如果您不关心性能,请注意可读性更重要,您可以简单地使用常规循环来实现它。此解决方案的另一个问题是您无法处理执行期间可能发生的意外异常,例如 TypeErros 等。
  • 性能比可读性很重要,我要转换4.5m数据!和他们的过程!所以知道这个事实你会推荐这个解决方案吗?
  • @Dariush:转换所需的时间可能只是从磁盘读取数据所需时间的一小部分,所以我不会太费心,除非你最后发现这是个问题。跨度>
  • @Dariush 那么为什么不使用Numbypandas 来处理数据,并在加载期间转换它们。这比 python 快得多。
【解决方案2】:

我喜欢这样清晰的代码:

from datetime import datetime

input_row = ['529997', '46623448', '2122110124', '2310', '2054',
             '2', '66', '', '2010/11/03-12:42:08', '26',
             'CLEARING', '781', '30', '3', '0', '0', '1']

_date = lambda x: datetime.strptime(x, "%Y/%m/%d-%H:%M:%S")
# only necessary because '' should be treated as 0
_int  = lambda x: int('0' + x)

# specify the type parsers for each column
parsers = 8 * [_int] + [_date, _int, str] + 6 * [_int]

output_row = [parse(input) for parse, input in zip(parsers, input_row)]

根据您的需要,使用迭代器而不是列表。这可以大大减少您需要的内存量。

【讨论】:

  • 为了可读性,我将接受您的回答,尽管@Kasramvd 的回答也是有效的。
【解决方案3】:

我开发了以下函数来转换4.5m行矩阵,无效数据类型异常也被考虑在内。虽然可以通过并行化过程来改进它,但它对我来说做得很好,值得我将它发布在这里。

def cnvt_data(mat):
    from datetime import datetime

    _date = lambda x: datetime.strptime(x, "%Y/%m/%d-%H:%M:%S")
    # only necessary because '' should be treated as 0
    _int  = lambda x: int('0' + x)

    # specify the type parsers for each column
    parsers = 8 * [_int] + [_date, _int, str] + 6 * [_int]

    def try_parse(parse, value, _def):
        try:
            return parse(value), True
        except ValueError:
            return _def, False

    matrix = [];

    for idx in range(len(mat)):
        try:
            row = mat[idx]
            matrix.append(np.asarray([parse(input) for parse, input in zip(parsers, row)]))
        except ValueError:
            l = [];
            matrix.append([])
            for _idx, args in enumerate(zip(parsers, row)):
                val, pres = try_parse(args[0], args[1], 0)
                matrix[-1].append(val)
                if(not pres): l.append(_idx);
            print "\r[Error] value error @row %d @indices(%s): replaced with 0" %(idx, ', '.join(str(x) for x in l))

        print "\r[.] %d%% converted" %(idx * 100/len(mat)),

    print "\r[+] 100% converted."

    return matrix

【讨论】:

    【解决方案4】:

    通常当人们询问阅读csv 文件时,我们会要求提供文件样本。我试图从字符串列表中重建你的行:

    In [590]: txt
    Out[590]: b'529997, 46623448, 2122110124, 2310, 2054, 2, 66, , 2010/11/03-12:42:08, 26, CLEARING, 781, 30, 3, 0, 0, 1'
    

    b 用于 Py3 中的字节串,这是 genfromtxt 期望其输入的方式)

    genfromtxt 需要一个文件名、打开的文件或任何提供它的行。所以行列表可以正常工作:

    使用dtype=None 它推断列类型。

    In [591]: data=np.genfromtxt([txt], dtype=None, delimiter=',', autostrip=True)
    In [592]: data
    Out[592]: 
    array((529997, 46623448, 2122110124, 2310, 2054, 2, 66, False, b'2010/11/03-12:42:08', 26, b'CLEARING', 781, 30, 3, 0, 0, 1), 
          dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<i4'), ('f5', '<i4'), ('f6', '<i4'), ('f7', '?'), ('f8', 'S19'), ('f9', '<i4'), ('f10', 'S8'), ('f11', '<i4'), ('f12', '<i4'), ('f13', '<i4'), ('f14', '<i4'), ('f15', '<i4'), ('f16', '<i4')])
    

    结果是一堆int字段,2个字符串字段。空白被解释为布尔值。

    如果我拼出列类型,我会得到一个稍微不同的数组

    In [593]: dt=[int,int,int,int,int,int,int,float,'U20',int, 'U10',int,int,int,int,int,int]
    In [594]: data=np.genfromtxt([txt], dtype=dt, delimiter=',', autostrip=True)
    In [595]: data
    Out[595]: 
    array((529997, 46623448, 2122110124, 2310, 2054, 2, 66, nan, '2010/11/03-12:42:08', 26, 'CLEARING', 781, 30, 3, 0, 0, 1), 
          dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<i4'), ('f5', '<i4'), ('f6', '<i4'), ('f7', '<f8'), ('f8', '<U20'), ('f9', '<i4'), ('f10', '<U10'), ('f11', '<i4'), ('f12', '<i4'), ('f13', '<i4'), ('f14', '<i4'), ('f15', '<i4'), ('f16', '<i4')])
    

    我为空白列指定了float,然后它将其解释为nan。对黑人的处理可以细化。

    我将字符串文件更改为 unicode(默认的 py3 字符串)。

    我应该能够指定日期时间转换,例如到np.datetime64

    只有一行,data 是一个单元素数组 0d,带有一个复合 dtype

    字段按名称访问

    In [598]: data['f8']
    Out[598]: 
    array('2010/11/03-12:42:08', 
          dtype='<U20')
    In [599]: data['f2']
    Out[599]: array(2122110124)
    

    速度方面,这可能与您的自定义阅读器相同。 genfromtxt 逐行读取文件,并对其进行解析。它将解析的行收集到一个列表中,并在最后创建一个数组(我不记得解析的行是列表还是 dtype 数组 - 我怀疑是列表,但必须研究代码)。

    要处理日期,我必须使用'datetime64[s]',以及一些如何将日期更改为"2010-11-03T12:42:08",可能是converter

    ====================

    我可以根据你的datetime解析做一个转换器:

    In [649]: from datetime import datetime
    In [650]: dateconvert=lambda x: datetime.strptime(x.decode(),"%Y/%m/%d-%H:%M:%S")
    In [651]: data=np.genfromtxt([txt], dtype=dt, delimiter=',',  autostrip=True, converters={8:dateconvert})
    In [652]: data
    Out[652]: 
    array((529997, 46623448, 2122110124, 2310, 2054, 2, 66, nan, datetime.datetime(2010, 11, 3, 12, 42, 8), 26, 'CLEARING', 781, 30, 3, 0, 0, 1), 
          dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<i4'), ('f5', '<i4'), ('f6', '<i4'), ('f7', '<f8'), ('f8', '<M8[s]'), ('f9', '<i4'), ('f10', '<U10'), ('f11', '<i4'), ('f12', '<i4'), ('f13', '<i4'), ('f14', '<i4'), ('f15', '<i4'), ('f16', '<i4')])
    

    【讨论】:

      猜你喜欢
      • 2014-04-02
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 2021-03-27
      • 2017-02-20
      • 2022-12-17
      • 1970-01-01
      相关资源
      最近更新 更多