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

7
我有数百个类似这样的文本文件,每列之间用三个空格分隔。数据是一年的数据:每个月有12个月和31天。
下面,我只展示与问题相关的内容:
001 DIST - ADILABAD ANDHRA 平均温度
 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非常陌生,并且仅在两周前开始学习。我在StackOverflow和Google上搜索了很多问题,并学习了如何跳过行、列等内容。但我找不到任何与这个特定问题相关的答案。

请建议一些模块、函数、代码等。

提前致谢。


根据您的建议,我传递了 filling_values=NaN ,但是出现了以下错误 NameError: name 'NaN' is not defined - user3707588
尝试使用numpy.NaN或甚至是0,有兴趣知道这是否有效。 - EdChum
它没有显示任何错误,但数组仍然有28个元素。并且没有填充NAN值。虽然我读过filling_values属性,但我没有使用它,认为我以后无法使用np.mean()来找到平均值。 - user3707588
很抱歉,我不知道如何在这里发布文本文件?我已经阅读了一些关于Pandas包的内容,但我不知道如何使用它。由于评论中允许的字符有限,我无法发布。 - user3707588
我的意思是像Dropbox或类似的链接。Pandas支持导入固定宽度文件。 - EdChum
显示剩余3条评论
2个回答

5
你的数据不是由文本进行“分隔”的,而是具有固定宽度的列。正如@EdChum在他的回答中所示,pandas有一个用于读取具有固定宽度列的数据的函数。您还可以使用genfromtxt,通过在delimiter参数中给出列宽来实现。看起来字段宽度为(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 也需要使用。如果您不使用这个参数,将会得到额外一行nan值的 data
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 会附加在最后面? - user3707588
我更新了我的回答。(4,) + (7,)*12 是“元组”算术:+ 表示连接,而一个元组和一个整数的 * 表示重复。该表达式等同于 (4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7) - Warren Weckesser
谢谢您,解释得非常好。它解决了我的问题,我可以问您一件事吗?正如我所提到的,我有数百个这样的文件,并且我想以这种方式在csv文件中获得平均值:district_name,JanAvg,FebAvg...DecAvg,那么我该如何读取这么多文件呢?我是Python和NumPy的新手,如果您能指向任何资源/教程等,将非常有帮助。我没有立即选择您的答案,因为我认为这会关闭线程。如果您不知道,也没关系,只是想听听您的建议。 - user3707588
最好是提出一个新问题,询问如何解决那个问题。 - Warren Weckesser
好的,我认为新手在StackOverflow上提问是有限制的。我会搜索和挖掘。无论如何,非常感谢你。自从周三以来我一直卡在这个问题上。已被选为答案。 :) - user3707588

4

更新

感谢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

一月份的平均值发生了什么? - Warren Weckesser
@WarrenWeckesser 很好的问题,由于某些原因它消失了。 - EdChum
我刚试了一下。read_fwf将文件中的前两列合并为一个名为DATE JAN的DataFrame列。该列中的值是字符串。例如,df['DATE JAN'][0]'01 21.5' - Warren Weckesser
@WarrenWeckesser 请看更新后的答案,我不得不从标题行中删除一个前导空格,这修复了不正确的对齐。 - EdChum
1
给出宽度明确的参数对我很有效:df = pd.read_fwf("temp_mean.txt", skiprows=2, widths=(5,)+(7,)*12)。这样就不需要编辑文件了。 - Warren Weckesser
感谢您一直陪伴我到现在,先生。我没有选择这个作为最终答案的唯一原因是,我不知道Pandas,而且在我已经非常紧张的时间表中学习它将是一个新任务。但它绝对值得研究。当我完成我的项目时,我会去学习它的。祝您有美好的一天 :) - user3707588

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接