【问题标题】:Programmatically add column names to numpy ndarray以编程方式将列名添加到 numpy ndarray
【发布时间】:2012-05-31 07:51:18
【问题描述】:

我正在尝试将列名添加到 numpy ndarray,然后按名称选择列。但它不起作用。我不知道是在添加名称时出现问题,还是在稍后尝试调用它们时出现问题。

这是我的代码。

data = np.genfromtxt(csv_file, delimiter=',', dtype=np.float, skip_header=1)

#Add headers
csv_names = [ s.strip('"') for s in file(csv_file,'r').readline().strip().split(',')]
data = data.astype(np.dtype( [(n, 'float64') for n in csv_names] ))

基于维度的诊断符合我的预期:

print len(csv_names)
>> 108
print data.shape
>> (1652, 108)

“print data.dtype.names”也返回预期的输出。

但是当我开始通过字段名称调用列时,就会发生一些奇怪的事情。 “列”仍然是一个有 108 列的数组...

print data["EDUC"].shape
>> (1652, 108)

...它似乎包含的缺失值比数据集中的行数多。

print np.sum(np.isnan(data["EDUC"]))
>> 27976

知道这里出了什么问题吗?添加标题应该是一个微不足道的操作,但我已经与这个错误作斗争了几个小时。救命!

【问题讨论】:

    标签: python arrays numpy multidimensional-array


    【解决方案1】:

    问题是您在考虑类似电子表格的数组,而 NumPy 使用不同的概念。

    关于 NumPy,您必须了解以下内容:

    1. NumPy 数组只包含单一类型的元素。
    2. 如果您需要类似电子表格的“列”,此类型必须是某种类似元组的类型。此类数组称为结构化数组,因为它们的元素是结构(即元组)。

    在您的情况下,NumPy 将因此获取您的二维常规数组并生成一个 one 维数组,其类型是 108 元素元组(您正在考虑的电子表格数组是 2维)。

    这些选择可能是出于效率原因:数组的所有元素都具有相同的类型,因此具有相同的大小:它们可以在低级别访问,非常简单和快速。

    现在,正如 user545424 所示,有一个简单的 NumPy 答案可以回答您想要做什么(genfromtxt() 接受带有列名的 names 参数)。

    如果您想将您的数组从常规 NumPy ndarray 转换为结构化数组,您可以这样做:

    data.view(dtype=[(n, 'float64') for n in csv_names]).reshape(len(data))
    

    (你很亲密:你使用了astype() 而不是view())。

    您还可以查看很多 Stackoverflow 问题的答案,包括 Converting a 2D numpy array to a structured arrayhow to convert regular numpy array to record array?

    【讨论】:

    • 谢谢——这有助于从概念上理清思路。但我仍然对这个特殊案例有一些疑问。在这里,我所有的列都是浮点数,我将做很多矩阵乘法,所以我想保留二维数组结构——不需要结构化数组。我想要做的就是添加字段名称。这可能吗?
    • 注意:genfromtxt 以 numpy 的结构化元组格式导入 csv。我尝试了所有我能想到的以数组格式导入字段名称,但没有任何效果。
    • @Abe:您仍然可以执行矩阵乘法:view() 只是查看 same 数据的另一种方式。因此,您可以同时使用原始数据数组和view()ed 数组(第一个数组是二维的,第二个是一维的并且是结构化的)。
    • @Abe:关于您的第二个问题:您不能拥有“(2D)数组格式的字段名称”。这个概念在 NumPy 中无效(这是一个电子表格概念)。您想要一个非结构化/命名列 2D 数组(您的 data 数组),或者它的一维结构化/命名列版本(view() 在我的回答中的结果)。我希望这将有助于解决问题。 :)
    • @Abe:从技术上讲,我不想让事情变得比现在更复杂,但请注意,您可以拥有一个 2D(或 n 维)结构化数组。然而,每个单元格将包含一个元组。示例:arr = zeros((3, 5), dtype=[('x', int), ('y', float)]),具有类似a['x'] 的结构访问,它返回整数的二维数组。
    【解决方案2】:

    不幸的是,当您尝试添加字段名称时,我不知道发生了什么,但我知道您可以直接从文件中构建您想要的数组通过

    data = np.genfromtxt(csv_file, delimiter=',', names=True)
    

    编辑:

    似乎添加字段名称仅在输入是元组列表时才有效:

    data = np.array(map(tuple,data), [(n, 'float64') for n in csv_names])
    

    【讨论】:

    • 那么,如果 ndarrays 被转换为元组,或者在转换为数组时被字段 id 引用,那么是否可以通过字段名称引用 ndarrays?这似乎是它的工作方式,但我在文档中没有看到类似的内容。
    • 我开始怀疑这是否是一个错误。根据您传入的嵌套结构的类型,让数组构造函数采取不同的行为是非常奇怪的行为。
    • @user545424:如果您了解 NumPy 所基于的原则,您就可以理解这种行为(例如,您可以查看我的答案)。简而言之:tuple() 是一种“基本类型”(如浮点数),对于 NumPy(因此当您传递元组时,您会得到一种结构化数组),而将列表或数组作为输入传递意味着“添加另一个维度" 到数组(通常会得到一个数字数组)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-17
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多