我该如何获取NumPy数组的描述性统计信息?

81

我使用以下代码创建一个numpy-ndarray。文件有9列,我显式地为每一列指定类型:

dataset = np.genfromtxt("data.csv", delimiter=",",dtype=('|S1', float, float,float,float,float,float,float,int))

现在我想要获取每一列的描述性统计信息(如最小值、最大值、标准差、平均值、中位数等)。难道没有简单的方法来实现吗?

我尝试了这个:

from scipy import stats
stats.describe(dataset)

但是这会返回一个错误:TypeError:无法对具有灵活类型的数组执行缩减操作

我如何获取创建的NumPy数组的描述性统计信息?


1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - M.T
2
@beta 如果你正在处理不均匀的数据(看起来是这样),你应该看一下 pandas,因为它对于这种情况更加强大。 - Holt
@M.T:然后我得到了ValueError: could not convert string to float: 'F'错误。 - beta
@Holt:我想使用numpy,因为我将与scikit-learn结合使用,并且许多示例都基于numpy... 我认为我不需要处理非均匀数据。我只有一列是字符串,因为它是分类数据。 - beta
1
如果没有给出字段名称,则默认字段名称为“'f0'”,“'f1'”等。因此,您可以使用stats.describe(dataset['f2']),而不是stats.describe(dataset[2]) - Warren Weckesser
显示剩余7条评论
5个回答

62
import pandas as pd
import numpy as np

df_describe = pd.DataFrame(dataset)
df_describe.describe()

请注意,数据集是您的np.array描述。

import pandas as pd
import numpy as np

df_describe = pd.DataFrame('your np.array')
df_describe.describe()

12
我认为这是最简单的选择。你甚至不需要创建一个新变量,只需编写 pd.DataFrame(my_array).describe() - kyriakosSt
1
对于OP提出的问题,我认为这个答案的代码应该是pd.read_csv("data.csv").describe(),而不是暗示数据首先加载到numpy数组中。 - kyriakosSt
2
只需一行代码,无需循环等复杂操作。这是最佳答案。 - agent18

33
这不是一个优美的解决方案,但它可以完成工作。问题在于通过指定多个数据类型,实质上你正在创建一个元组的1D数组(实际上是np.void),这不能被统计描述,因为它包含多种不同的类型,包括字符串。
要解决这个问题,可以通过两轮读取或使用带有read_csv的 Pandas 解决。
如果你决定坚持使用 numpy:
import numpy as np
a = np.genfromtxt('sample.txt', delimiter=",",unpack=True,usecols=range(1,9))
s = np.genfromtxt('sample.txt', delimiter=",",unpack=True,usecols=0,dtype='|S1')

from scipy import stats
for arr in a: #do not need the loop at this point, but looks prettier
    print(stats.describe(arr))
#Output per print:
DescribeResult(nobs=6, minmax=(0.34999999999999998, 0.70999999999999996), mean=0.54500000000000004, variance=0.016599999999999997, skewness=-0.3049304880932534, kurtosis=-0.9943046886340534)

请注意,此示例中的最终数组具有dtypefloat,而不是 int,但可以轻松地(如果需要)使用arr.astype(int)将其转换为整数。


这种使用 usecols 的方式很好。我认为你不需要使用 unpack - hpaulj
@hpaulj 如果按照您在答案中展示的方式访问数据(我认为这个答案值得被接受),那么解压是不必要的。然而,根据我的经验,无论是使用genfromtxt还是loadtxt,当处理来自类似csv的科学数据时,我总是使用列(即正常输出的转置)进行操作。同时,循环遍历recarray字段也不太容易。 - M.T
我已经为嵌套结构打开了一个衍生问题,请参见 https://stackoverflow.com/questions/62385252/how-can-i-get-the-statistics-of-all-columns-including-those-with-a-nested-struct/62385253#62385253 - questionto42

7

如何处理来自genfromtxt的混合数据是一个经常出现的问题。人们期望得到一个二维数组,但实际上会得到一个无法按列索引的一维数组。这是因为他们得到了一个结构化数组——每个列具有不同的数据类型。

genfromtxt文档中的所有示例都展示了这一点:

>>> s = StringIO("1,1.3,abcde")
>>> data = np.genfromtxt(s, dtype=[('myint','i8'),('myfloat','f8'),
... ('mystring','S5')], delimiter=",")
>>> data
array((1, 1.3, 'abcde'),
      dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', '|S5')])

但让我演示如何访问这种数据。
In [361]: txt=b"""A, 1,2,3
     ...: B,4,5,6
     ...: """
In [362]: data=np.genfromtxt(txt.splitlines(),delimiter=',',dtype=('S1,int,float,int'))
In [363]: data
Out[363]: 
array([(b'A', 1, 2.0, 3), (b'B', 4, 5.0, 6)], 
      dtype=[('f0', 'S1'), ('f1', '<i4'), ('f2', '<f8'), ('f3', '<i4')])

因此,我的数组有2条记录(检查形状),它们以列表中的元组形式显示。

您可以通过名称访问fields,而不是通过列编号(我需要添加一个结构化数组文档链接吗?)

In [364]: data['f0']
Out[364]: 
array([b'A', b'B'], 
      dtype='|S1')
In [365]: data['f1']
Out[365]: array([1, 4])

在这种情况下,如果我选择一个具有“子数组”的 dtype 可能更加有用。这是一个更高级的 dtype 主题。
In [367]: data=np.genfromtxt(txt.splitlines(),delimiter=',',dtype=('S1,(3)float'))
In [368]: data
Out[368]: 
array([(b'A', [1.0, 2.0, 3.0]), (b'B', [4.0, 5.0, 6.0])], 
      dtype=[('f0', 'S1'), ('f1', '<f8', (3,))])
In [369]: data['f1']
Out[369]: 
array([[ 1.,  2.,  3.],
       [ 4.,  5.,  6.]])

字符列仍然被加载为S1,但数字现在是一个包含3个列的数组。请注意,它们都是浮点数(或整数)。

In [371]: from scipy import stats
In [372]: stats.describe(data['f1'])
Out[372]: DescribeResult(nobs=2, 
   minmax=(array([ 1.,  2.,  3.]), array([ 4.,  5.,  6.])),
   mean=array([ 2.5,  3.5,  4.5]), 
   variance=array([ 4.5,  4.5,  4.5]), 
   skewness=array([ 0.,  0.,  0.]), 
   kurtosis=array([-2., -2., -2.]))

3

官方Scipy文档 示例

#INPUT
from scipy import stats
a = np.arange(10)
stats.describe(a)

#OUTPUT
DescribeResult(nobs=10, minmax=(0, 9), mean=4.5, variance=9.166666666666666,
               skewness=0.0, kurtosis=-1.2242424242424244)

#INPUT
b = [[1, 2], [3, 4]]
stats.describe(b)

#OUTPUT
DescribeResult(nobs=2, minmax=(array([1, 2]), array([3, 4])),
               mean=array([2., 3.]), variance=array([2., 2.]),
               skewness=array([0., 0.]), kurtosis=array([-2., -2.]))

0

对于那些需要进行快速计算的人来说,scipy + numpy 比 pandas 更快:

# scipy + numpy
def get_stats(v):
    res = stats.describe(v)
    return np.concatenate([
        [
            res.minmax[0],
            res.minmax[1],
            res.mean,
            res.variance,
            res.skewness,
            res.kurtosis
        ],
        np.percentile(v, q=[10, 25, 50, 75, 90])
    ])

%timeit get_stats(np.arange(100))
639 µs ± 11.3 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%timeit pd.Series(np.arange(100)).describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9])
830 µs ± 31.1 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

另外,在 describe() 中,pandas 没有提取出 kurtosisskewness


警告:使用 pd.DataFrame(array).describe() 速度较慢:

%timeit pd.DataFrame(np.arange(100)).describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9])
1.43 ms ± 75.6 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

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