如何使用 genfromtxt() 从 NumPy 中的文本文件中读取不同长度的列?

Posted

技术标签:

【中文标题】如何使用 genfromtxt() 从 NumPy 中的文本文件中读取不同长度的列?【英文标题】:How to read columns of varying length from a text file in NumPy using genfromtxt()? 【发布时间】:2014-07-27 14:25:07 【问题描述】:

我有数百个这样的文本文件,每列用三个空格分隔。数据为一年:每月 12 个月 31 天。

下面,我只在下面显示与问题相关的内容:

001 DIST - 阿迪巴德安得拉平均温度

 DATE  JAN    FEB    MAR . . . .  NOV    DEC  
 01    21.5   24.3   27.1         25.8   22.4  
 02    21.4   24.2   27.1         25.8   22.4  
 .        .      .      .            .      .
 .        .      .      .            .      .
 .        .      .      .            .      . 
 27    23.6   26.8   30.3         23.1   21.3  
 28    23.8   27.0   30.6         22.9   21.3  
 29    23.4          31.0         22.9   21.2  
 30    23.5          31.1         22.6   21.4  
 31    23.8          31.2 . . . .        21.6  

我想将每一列读入一个数组,然后对其进行平均。

为此,我正在使用genfromtext() 函数,如下所示:

import numpy as np
JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC = np.genfromtxt("tempmean_andhra_adilabad.txt", skiprows=3, 
                                                                 unpack=True, invalid_raise=False, 
                                                                 usecols=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 
                                                                 autostrip=True)

如您所见,我已跳过前三行和第一列,并将每一列解压缩到一个数组中。没有invalid_raise=False,我收到以下错误:

Traceback (most recent call last):

File "pyshell#32", line 1, in 'module'  
JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC = np.genfromtxt("temp mean_andhra_adilabad.txt",skiprows=3,unpack=True,usecols=(1,2,3,4,5,6,7,8,9,10,11,12),autostrip=True)  
File "C:\Python27\lib\site-packages\numpy\lib\npyio.py", line 1667, in genfromtxt
raise ValueError(errmsg)  

ValueError: Some errors were detected !  
Line #32 (got 12 columns instead of 12)  
Line #33 (got 12 columns instead of 12)  
Line #34 (got 8 columns instead of 12)  

我认为这个问题是因为列的长度不同?还是其他什么原因?

我想查看输出,所以我使用了invalid_raise=False。现在我的问题是,当我打印任何数组时,比如JAN,我只会得到 28 个元素。即每个数组只有 28 个元素。似乎每列只读取 28 行,因为 FEB 列以 28 天结束。但我需要每个月的数据,即JAN 31 个元素JUNE 等 30 个元素。

如何获取每个月的所有元素?

我认为这是一个非常基本的问题,但我对 Python 和 NumPy 非常陌生,两周前才开始学习。我在 *** 和 Google 上搜索了很多问题,并了解了如何跳过行、列等。但我找不到与这个特定问题相关的任何答案。

请推荐一些模块、功能、代码等。

提前致谢。

【问题讨论】:

如果您将filling_values=NaN 作为参数传递会发生什么? 根据您的建议,我通过了filling_values=NaN 并收到以下错误NameError: name 'NaN' is not defined 试试numpy.NaN 甚至0,有兴趣知道这是否有效 它没有显示任何错误,但数组仍然有 28 个元素。并且没有填充 NAN 值。虽然我读过filling_values 属性,但我没有使用它,因为我认为以后无法使用np.mean() 来找到平均值。 能否发下数据或链接,可能 Pandas 可以处理,pandas 使用 numpy 存储数据 【参考方案1】:

您的数据不是由文本“分隔”的。相反,它具有固定宽度的列。正如@EdChum 在他的回答中显示的那样,pandas 具有读取具有固定宽度列的数据的功能。您还可以通过在delimiter 参数中指定列宽来使用genfromtxt。看起来字段宽度是 (4, 7, 7, 7, ...)。在下面的代码中,我会写成(4,) + (7,)*12

In [27]: (4,) + (7,)*12
Out[27]: (4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7)

genfromtxt 使用的默认数据类型是np.float64。如果一个字段不能转换为浮点数,它将被替换为nan。因此,少于 31 天的月末数据将是 nan

在下文中,我将您的文件重命名为“temp_mean.txt”。请注意,您的文件末尾有一个额外的空白行,因此还使用了参数skip_footer=1。如果您不使用此参数,您将在data 中获得额外的一行nan 值。

In [16]: data = genfromtxt("temp_mean.txt", skiprows=3, delimiter=(4,)+(7,)*12, usecols=range(1,13), skip_footer=1)

In [17]: data.shape
Out[17]: (31, 12)

In [18]: data[:,0]  # JAN
Out[18]: 
array([ 21.5,  21.4,  21.2,  21.2,  21.4,  21.7,  21.8,  22. ,  22. ,
        22.3,  22.3,  22.3,  22.5,  22.5,  22.5,  22.5,  22.5,  22.6,
        22.8,  23.1,  23.1,  22.8,  22.9,  23.1,  23.4,  23.5,  23.6,
        23.8,  23.4,  23.5,  23.8])

In [19]: data[:,1]  # FEB
Out[19]: 
array([ 24.3,  24.2,  24.3,  24.4,  24.6,  24.4,  24.1,  24.4,  24.5,
        24.6,  24.9,  25. ,  25.1,  25.6,  25.7,  25.7,  25.8,  26. ,
        25.9,  25.9,  25.8,  25.8,  25.8,  26.2,  26.5,  26.7,  26.8,
        27. ,   nan,   nan,   nan])

In [20]: data[-1,:]  # Last row.
Out[20]: 
array([ 23.8,   nan,  31.2,   nan,  34.7,   nan,  27.4,  27. ,   nan,
        25.7,   nan,  21.6])

要获取月均值,可以使用np.nanmean

In [21]: np.nanmean(data, axis=0)
Out[21]: 
array([ 22.5483871 ,  25.35714286,  29.22903226,  32.79333333,
        34.65806452,  31.19666667,  27.89032258,  27.01612903,
        27.66666667,  27.22580645,  24.34666667,  21.81290323])

【讨论】:

谢谢,它正在工作。你能解释一下delimiter做了什么吗?我知道宽度是 (4,7,7,..) 但delimiter[(4,)+(7,)*12] 的值是正则表达式吗?当您不使用 filling_values 时,最后如何附加 NaN? 我更新了我的答案。 (4,) + (7,)*12 是“元组”算术:+ 进行连接,* 使用元组和整数进行重复。该表达式等价于(4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7) 谢谢先生,很好的解释。它解决了问题,我能问你一件事吗,正如我提到的那样,我有数百个这样的文件,我想以这种方式在 csv 文件中获取平均值:district_name,JanAvg,FebAvg...DecAvg,那么我怎么能读取这么多文件?我是 Python 和 NumPy 的新手,您可以指出的任何资源/教程等都会非常有帮助。而且我没有立即选择您的答案,因为我认为这会关闭线程。不知道也没关系,只是想看看你的建议。 最好提出一个关于如何解决该问题的新问题。 好的,我认为新手可以在 *** 上提问是有限制的。我会搜索和我的。无论如何,非常感谢你。从星期三开始,我就一直坚持这个。被选为答案。 :)【参考方案2】:

更新

感谢 Warren Weckesser 指出您可以传递正确处理此文件的宽度值

好的,pandas 可以很好地读取固定宽度的文件:

In [192]:

df = pd.read_fwf(r'c:\data\temp mean_andhra_adilabad.txt',skiprows=2, widths=(5,)+(7,)*12, skip_footer=1)
df
Out[192]:
    DATE   JAN   FEB   MAR   APR   MAY   JUN   JUL   AUG   SEP   OCT   NOV  \
0      1  21.5  24.3  27.1  31.3  34.1  34.5  29.0  27.5  27.1  28.0  25.8   
1      2  21.4  24.2  27.1  31.4  33.8  34.1  28.8  27.5  27.1  28.0  25.8   
2      3  21.2  24.3  27.1  31.5  34.4  34.1  28.6  27.5  27.0  28.0  25.6   
3      4  21.2  24.4  27.1  31.7  34.4  33.8  28.5  27.1  27.0  27.9  25.5   
4      5  21.4  24.6  27.6  31.7  34.4  33.5  28.2  27.0  27.1  27.8  25.4   
5      6  21.7  24.4  28.0  31.6  34.5  33.3  28.2  27.1  27.0  28.0  25.1   
6      7  21.8  24.1  28.1  31.5  34.5  32.9  28.2  27.1  27.0  27.8  25.3   
7      8  22.0  24.4  28.3  31.8  34.6  33.3  27.9  26.7  27.1  27.9  25.1   
8      9  22.0  24.5  28.3  32.2  34.6  33.1  27.8  26.6  27.2  28.1  24.8   
9     10  22.3  24.6  28.4  32.1  34.5  32.5  28.0  26.7  27.2  27.9  25.0   
10    11  22.3  24.9  28.6  32.3  34.4  32.2  27.8  26.9  27.2  28.0  25.2   
11    12  22.3  25.0  28.3  32.6  34.4  32.0  27.6  27.1  27.3  27.9  24.9   
12    13  22.5  25.1  28.6  32.7  34.5  31.4  27.8  27.1  27.5  27.8  24.8   
13    14  22.5  25.6  28.7  33.1  34.7  31.2  27.7  26.8  27.6  27.7  24.6   
14    15  22.5  25.7  29.1  33.2  34.6  31.0  27.8  27.0  27.9  27.6  24.6   
15    16  22.5  25.7  29.4  33.1  34.4  30.6  27.7  26.9  28.0  27.6  24.5   
16    17  22.5  25.8  29.5  32.8  34.6  30.1  27.8  26.8  28.1  27.2  24.3   
17    18  22.6  26.0  29.9  33.0  34.8  30.1  27.6  27.0  28.2  27.3  24.0   
18    19  22.8  25.9  30.2  33.3  34.7  30.0  27.9  27.0  28.1  27.2  24.0   
19    20  23.1  25.9  30.2  33.3  35.1  30.2  27.9  27.0  27.9  27.2  24.0   
20    21  23.1  25.8  30.2  33.5  34.9  30.1  27.8  26.9  28.0  26.9  23.8   
21    22  22.8  25.8  30.6  33.4  35.1  29.8  27.8  26.8  28.2  26.7  23.5   
22    23  22.9  25.8  30.6  33.4  35.1  29.6  27.8  26.8  28.2  26.7  23.5   
23    24  23.1  26.2  30.4  33.5  35.1  29.3  27.8  27.0  28.1  26.5  23.5   
24    25  23.4  26.5  30.2  33.5  35.1  29.2  27.6  27.3  28.1  26.5  23.3   
25    26  23.5  26.7  30.3  33.6  35.0  29.1  27.6  27.4  28.2  26.4  23.0   
26    27  23.6  26.8  30.3  33.8  35.1  28.8  27.6  27.1  28.2  26.2  23.1   
27    28  23.8  27.0  30.6  34.1  34.9  28.5  27.6  26.8  28.2  26.0  22.9   
28    29  23.4   NaN  31.0  34.3  34.8  28.5  27.4  27.0  28.1  25.8  22.9   
29    30  23.5   NaN  31.1  34.5  34.6  29.1  27.4  27.0  28.1  25.7  22.6   
30    31  23.8   NaN  31.2   NaN  34.7   NaN  27.4  27.0   NaN  25.7   NaN   

     DEC  
0   22.4  
1   22.4  
2   22.5  
3   22.5  
4   22.6  
5   22.3  
6   22.0  
7   22.0  
8   21.8  
9   21.7  
10  21.9  
11  21.9  
12  21.8  
13  21.5  
14  21.5  
15  21.5  
16  21.7  
17  21.6  
18  21.7  
19  21.7  
20  21.8  
21  21.7  
22  21.8  
23  21.8  
24  21.7  
25  21.6  
26  21.3  
27  21.3  
28  21.2  
29  21.4  
30  21.6  

In [193]:
df.mean(axis=0)
Out[193]:
DATE    16.000000
JAN     22.548387
FEB     25.357143
MAR     29.229032
APR     32.793333
MAY     34.658065
JUN     31.196667
JUL     27.890323
AUG     27.016129
SEP     27.666667
OCT     27.225806
NOV     24.346667
DEC     21.812903
dtype: float64

【讨论】:

一月份的平均值发生了什么变化? @WarrenWeckesser 好问题,由于某种原因它掉线了 我刚试过这个。 read_fwf 将文件中的前两列合并到 DataFrame 中的单个列中,标题为 DATE JAN。此列中的值是字符串。例如df['DATE JAN'][0]'01 21.5' @WarrenWeckesser 请查看更新的答案,我必须从标题行中删除前导空格,这修复了不正确的对齐方式 明确指定宽度对我有用:df = pd.read_fwf("temp_mean.txt", skiprows=2, widths=(5,)+(7,)*12)。则无需编辑文件。

以上是关于如何使用 genfromtxt() 从 NumPy 中的文本文件中读取不同长度的列?的主要内容,如果未能解决你的问题,请参考以下文章

NumPy之:使用genfromtxt导入数据

使用 numpy.genfromtxt 在 Python 3 中加载 UTF-8 文件

numpy genfromtxt IndexError 使用评论时

Numpy使用genfromtxt解析日期

使用 numpy.genfromtxt 读取包含逗号的字符串的 csv 文件

numpy.genfromtxt 导入元组而不是数组