如何转换混合数据类型的字符串数组

时间:2016-09-09 09:26:47

标签: python arrays numpy converter mixed

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

# 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 行数据然后处理它们!

4 个答案:

答案 0 :(得分:2)

这是列表理解的一个线性:

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]

答案 1 :(得分:1)

我喜欢这样的明确代码:

conda

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

答案 2 :(得分:1)

我开发了以下函数来转换矩阵的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

答案 3 :(得分:1)

通常当人们询问阅读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'

(Py3中的bytestring的b,这是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')])