美文网首页
《利用Python进行数据分析》第五章 pandas的数据汇总与

《利用Python进行数据分析》第五章 pandas的数据汇总与

作者: 龍猫君 | 来源:发表于2017-12-13 23:53 被阅读0次

    汇总和计算描述统计

    pandas对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值(如sum或mean)或从DataFrame的行或列中提取一个Series。

    In [1]: from pandas import Series,DataFrame
    In [2]: import pandas as pd
    In [3]: import numpy as np
    

    用DataFrame的sum方法将会返回一个含有列小计的Series:

    In [5]: df=DataFrame([[2.6,np.nan],[6.2,-3.5],
       ...: [np.nan,np.nan],[0.75,-1.3]],
       ...: index=['a','b','c','d'],
       ...: columns=['one','two'])
    
    In [6]: df
    Out[6]: 
    one two
    a 2.60 NaN
    b 6.20 -3.5
    c NaN NaN
    d 0.75 -1.3
    
    In [7]: df.sum()
    Out[7]: 
    one 9.55
    two -4.80
    dtype: float64
    

    传入axis=1将会按行进行求和运算

    In [8]: df.sum(axis=1)
    Out[8]: 
    a 2.60
    b 2.70
    c 0.00
    d -0.55
    dtype: float64
    

    NA值会自动被排除,除非整个切片(这里指的是行或列)都是NA。通过skipna选项可以禁用该功能

    In [9]: df.mean(axis=1)
    Out[9]: 
    a 2.600
    b 1.350
    c NaN
    d -0.275
    dtype: float64
    
    In [10]: df.mean(axis=1,skipna=False)
    Out[10]: 
    a NaN
    b 1.350
    c NaN
    d -0.275
    dtype: float64
    

    idxmin和idxmax返回的是间接统计(比如达到最小值或最大值的索引

    In [11]: df.idxmax()
    Out[11]: 
    one b
    two d
    dtype: object
    
    In [12]: df.idxmin()
    Out[12]: 
    one d
    two b
    dtype: object
    

    累计型的

    In [13]: df.cumsum()
    Out[13]: 
    one two
    a 2.60 NaN
    b 8.80 -3.5
    c NaN NaN
    d 9.55 -4.8
    

    describe用于一次性产生多个汇总统计

    In [14]: df.describe()
    Out[14]: 
    one two
    count 3.000000 2.000000
    mean 3.183333 -2.400000
    std 2.771432 1.555635
    min 0.750000 -3.500000
    25% 1.675000 -2.950000
    50% 2.600000 -2.400000
    75% 4.400000 -1.850000
    max 6.200000 -1.300000
    

    对于非数值型数据,describe会产生另外一种汇总统计

    In [15]: obj=Series(['a','a','b','c']*4)
    
    In [16]: obj
    Out[16]: 
    0 a
    1 a
    2 b
    3 c
    4 a
    5 a
    6 b
    7 c
    8 a
    9 a
    10 b
    11 c
    12 a
    13 a
    14 b
    15 c
    dtype: object
    
    In [17]: obj.describe()
    Out[17]: 
    count 16
    unique 3
    top a
    freq 8
    dtype: object
    

    唯一值、值计数以及成员资格
    第一个函数是unique,它可以得到Series中的唯一值数组

    In [4]: obj = Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
    
    In [5]: uniques=obj.unique()
    
    In [6]: uniques
    Out[6]: array(['c', 'a', 'd', 'b'], dtype=object)
    

    返回的唯一值是未排序的,如果需要的话,可以对结果再次进行排序(uniques.sort())。value_counts用于计算一个Series中各值出现的频率

    In [7]: obj.value_counts()
    Out[7]: 
    c 3
    a 3
    b 2
    d 1
    dtype: int64
    

    结果Series是按值频率降序排列的。value_counts还是一个顶级pandas方法,可用于任何数组或序列

    In [12]: pd.value_counts(obj.values,sort=False)
    Out[12]: 
    d 1
    a 3
    b 2
    c 3
    dtype: int64
    

    isin,它用于判断矢量化集合的成员资格,可用于选取Series中或DataFrame列中数据的子集

    In [13]: mask=obj.isin(['b','c'])
    
    In [14]: mask
    Out[14]: 
    0 True
    1 False
    2 False
    3 False
    4 False
    5 True
    6 True
    7 True
    8 True
    dtype: bool
    
    In [15]: obj[mask]
    Out[15]: 
    0 c
    5 b
    6 b
    7 c
    8 c
    dtype: object
    

    有时可能希望得到DataFrame中多个相关列的一张柱状图

    In [16]: data = DataFrame({'Qu1': [1, 3, 4, 3, 4],
        ...: 'Qu2': [2, 3, 1, 2, 3],
        ...: 'Qu3': [1, 5, 2, 4, 4]})
    
    In [17]: data
    Out[17]: 
    Qu1 Qu2 Qu3
    0 1 2 1
    1 3 3 5
    2 4 1 2
    3 3 2 4
    4 4 3 4
    
    In [18]: result = data.apply(pd.value_counts).fillna(0)
    
    In [19]: result
    Out[19]: 
    Qu1 Qu2 Qu3
    1 1.0 1.0 1.0
    2 0.0 2.0 1.0
    3 2.0 2.0 0.0
    4 2.0 0.0 2.0
    5 0.0 0.0 1.0
    

    处理缺失数据

    pandas使用浮点值NaN(Not a Number)表示浮点和非浮点数组中的缺失数据

    In [20]: string_data = Series(['aardvark', 'artichoke', np.nan, 'avocado'])
    
    In [21]: string_data
    Out[21]: 
    0 aardvark
    1 artichoke
    2 NaN
    3 avocado
    dtype: object
    
    In [22]: string_data.isnull()
    Out[22]: 
    0 False
    1 False
    2 True
    3 False
    dtype: bool
    

    Python内置的None值也会被当做NA处理

    In [23]: string_data[0] = None
    
    In [24]: string_data
    Out[24]: 
    0 None
    1 artichoke
    2 NaN
    3 avocado
    dtype: object
    
    In [25]: string_data.isnull()
    Out[25]: 
    0 True
    1 False
    2 True
    3 False
    dtype: bool
    

    滤除缺失数据
    纯手工操作永远都是一个办法,但dropna可能会更实用一些。对于一个Series,dropna返回一个仅含非空数据和索引值的Series

    In [26]: from numpy import nan as NA
    
    In [27]: data = Series([3, NA, 3.5, NA, 9,5,NA])
    
    In [28]: data
    Out[28]: 
    0 3.0
    1 NaN
    2 3.5
    3 NaN
    4 9.0
    5 5.0
    6 NaN
    dtype: float64
    
    In [29]: data.dropna()
    Out[29]: 
    0 3.0
    2 3.5
    4 9.0
    5 5.0
    dtype: float64
    

    也可以通过布尔型索引达到这个目的

    In [30]: data[data.notnull()]
    Out[30]: 
    0 3.0
    2 3.5
    4 9.0
    5 5.0
    dtype: float64
    

    对于DataFrame对象,可能希望丢弃全NA或含有NA的行或列。dropna默认丢弃任何含有缺失值的行:

    In [31]: data = DataFrame([[3, 6.5, 9], [6., NA, NA],
        ...: [NA, NA, NA], [NA, 6.5, 8]])
    
    In [32]: data
    Out[32]: 
    0 1 2
    0 3.0 6.5 9.0
    1 6.0 NaN NaN
    2 NaN NaN NaN
    3 NaN 6.5 8.0
    
    In [33]: cleaned=data.dropna()
    
    In [34]: cleaned
    Out[34]: 
    0 1 2
    0 3.0 6.5 9.0
    

    传入how='all'将只丢弃全为NA的那些行

    In [35]: data.dropna(how='all')
    Out[35]: 
    0 1 2
    0 3.0 6.5 9.0
    1 6.0 NaN NaN
    3 NaN 6.5 8.0
    
    In [36]: data[4]=NA
    
    In [37]: data
    Out[37]: 
    0 1 2 4
    0 3.0 6.5 9.0 NaN
    1 6.0 NaN NaN NaN
    2 NaN NaN NaN NaN
    3 NaN 6.5 8.0 NaN
    

    要用这种方式丢弃列,只需传入axis=1

    In [38]: data.dropna(axis=1,how='all')
    Out[38]: 
    0 1 2
    0 3.0 6.5 9.0
    1 6.0 NaN NaN
    2 NaN NaN NaN
    3 NaN 6.5 8.0
    

    另一个滤除DataFrame行的问题涉及时间序列数据。假设你只想留下一部分观测数据,可以用thresh参数实现此目的

    In [39]: df = DataFrame(np.random.randn(7, 3))
    
    In [40]: df
    Out[40]: 
    0 1 2
    0 -0.668307 0.695528 -1.519538
    1 -0.623535 -0.157634 -0.197022
    2 0.064474 1.691703 -0.505063
    3 -1.146467 0.851013 0.203486
    4 1.910628 -0.309901 0.232673
    5 1.113025 0.883580 0.434787
    6 0.382675 1.488205 0.195079
    
    In [41]: df.ix[:4,1]=NA
    C:\ProgramData\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: DeprecationWarning: 
    .ix is deprecated. Please use
    .loc for label based indexing or
    .iloc for positional indexing
    
    See the documentation here:
    http://pandas.pydata.org/pandas-docs/stable/indexing.html#deprecate_ix
    """Entry point for launching an IPython kernel.
    
    In [42]: df.loc[:4,1]=NA
    
    In [43]: df
    Out[43]: 
    0 1 2
    0 -0.668307 NaN -1.519538
    1 -0.623535 NaN -0.197022
    2 0.064474 NaN -0.505063
    3 -1.146467 NaN 0.203486
    4 1.910628 NaN 0.232673
    5 1.113025 0.883580 0.434787
    6 0.382675 1.488205 0.195079
    
    In [44]: df.ix[:2,2]=NA
    
    In [45]: df
    Out[45]: 
    0 1 2
    0 -0.668307 NaN NaN
    1 -0.623535 NaN NaN
    2 0.064474 NaN NaN
    3 -1.146467 NaN 0.203486
    4 1.910628 NaN 0.232673
    5 1.113025 0.883580 0.434787
    6 0.382675 1.488205 0.195079
    

    填充缺失数据
    你可能不想滤除缺失数据(有可能会丢弃跟它有关的其他数据),而是希望通过其他方式填补那些“空洞”。对于大多数情况而言,fillna方法是最主要的函数。通过一个常数调用fillna就会将缺失值替换为那个常数值。

    In [46]: df.fillna(0)
    Out[46]: 
    0 1 2
    0 -0.668307 0.000000 0.000000
    1 -0.623535 0.000000 0.000000
    2 0.064474 0.000000 0.000000
    3 -1.146467 0.000000 0.203486
    4 1.910628 0.000000 0.232673
    5 1.113025 0.883580 0.434787
    6 0.382675 1.488205 0.195079
    

    若是通过一个字典调用fillna,就可以实现对不同的列填充不同的值

    In [47]: df.fillna({1:0.6,2:-3})
    Out[47]: 
    0 1 2
    0 -0.668307 0.600000 -3.000000
    1 -0.623535 0.600000 -3.000000
    2 0.064474 0.600000 -3.000000
    3 -1.146467 0.600000 0.203486
    4 1.910628 0.600000 0.232673
    5 1.113025 0.883580 0.434787
    6 0.382675 1.488205 0.195079
    
    In [48]: df
    Out[48]: 
    0 1 2
    0 -0.668307 NaN NaN
    1 -0.623535 NaN NaN
    2 0.064474 NaN NaN
    3 -1.146467 NaN 0.203486
    4 1.910628 NaN 0.232673
    5 1.113025 0.883580 0.434787
    6 0.382675 1.488205 0.195079
    

    fillna默认会返回新对象,但也可以对现有对象进行就地修改,总是返回被填充对象的引用

    In [49]: _=df.fillna(0,inplace=True)
    
    In [50]: df
    Out[50]: 
    0 1 2
    0 -0.668307 0.000000 0.000000
    1 -0.623535 0.000000 0.000000
    2 0.064474 0.000000 0.000000
    3 -1.146467 0.000000 0.203486
    4 1.910628 0.000000 0.232673
    5 1.113025 0.883580 0.434787
    6 0.382675 1.488205 0.195079
    

    对reindex有效的那些插值方法也可用于fillna

    In [56]: df = DataFrame(np.random.randn(6, 4))
    
    In [57]: df.loc[2:,1]=NA
    
    In [58]: df
    Out[58]: 
    0 1 2 3
    0 -0.104469 -0.311641 -0.190943 1.291739
    1 0.207564 1.413073 0.025226 1.215066
    2 -0.190017 NaN -1.240705 -0.177461
    3 0.270217 NaN -0.356850 -0.796403
    4 -1.628883 NaN -0.208336 -0.075219
    5 -1.576697 NaN 0.781700 -0.028192
    
    In [59]: df.loc[4:,2]=NA
    
    In [60]: df
    Out[60]: 
    0 1 2 3
    0 -0.104469 -0.311641 -0.190943 1.291739
    1 0.207564 1.413073 0.025226 1.215066
    2 -0.190017 NaN -1.240705 -0.177461
    3 0.270217 NaN -0.356850 -0.796403
    4 -1.628883 NaN NaN -0.075219
    5 -1.576697 NaN NaN -0.028192
    
    In [62]: df.fillna(method='ffill')
    Out[62]: 
    0 1 2 3
    0 -0.104469 -0.311641 -0.190943 1.291739
    1 0.207564 1.413073 0.025226 1.215066
    2 -0.190017 1.413073 -1.240705 -0.177461
    3 0.270217 1.413073 -0.356850 -0.796403
    4 -1.628883 1.413073 -0.356850 -0.075219
    5 -1.576697 1.413073 -0.356850 -0.028192
    

    可以连续填充的最大数量

    In [64]: df.fillna(method='ffill',limit=2)
    Out[64]: 
    0 1 2 3
    0 -0.104469 -0.311641 -0.190943 1.291739
    1 0.207564 1.413073 0.025226 1.215066
    2 -0.190017 1.413073 -1.240705 -0.177461
    3 0.270217 1.413073 -0.356850 -0.796403
    4 -1.628883 NaN -0.356850 -0.075219
    5 -1.576697 NaN -0.356850 -0.028192
    

    可以传入Series的平均值或中位数

    In [65]: data = Series([1., NA, 3.5, NA, 7])
    
    In [66]: data
    Out[66]: 
    0 1.0
    1 NaN
    2 3.5
    3 NaN
    4 7.0
    dtype: float64
    
    In [67]: data.fillna(data.mean())
    Out[67]: 
    0 1.000000
    1 3.833333
    2 3.500000
    3 3.833333
    4 7.000000
    dtype: float64
    

    层次化索引
    层次化索引(hierarchical indexing)是pandas的一项重要功能,它使你能在一个轴上拥有多个(两个以上)索引级别。抽象点说,它使你能以低维度形式处理高维度数据。

    In [1]: from pandas import Series,DataFrame
    
    In [2]: import pandas as pd
    
    In [3]: import numpy as np
    
    In [4]: data = Series(np.random.randn(10),
       ...: index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'],
       ...: [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
    
    In [5]: data
    Out[5]: 
    a 1 -1.155262
    2 1.141384
    3 -1.046202
    b 1 -0.621072
    2 -0.200051
    3 -0.812091
    c 1 1.762207
    2 0.293709
    d 2 -0.646778
    3 1.622014
    dtype: float64
    

    这就是带有MultiIndex索引的Series的格式化输出形式。索引之间的“间隔”表示“直接使用上面的标签

    In [6]: data.index
    Out[6]: 
    MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
    labels=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 2]])
    

    对于一个层次化索引的对象,选取数据子集的操作很简单

    In [8]: data['b']
    Out[8]: 
    1 -0.621072
    2 -0.200051
    3 -0.812091
    dtype: float64
    
    In [9]: data['b':'c']
    Out[9]: 
    b 1 -0.621072
    2 -0.200051
    3 -0.812091
    c 1 1.762207
    2 0.293709
    dtype: float64
    
    In [10]: data.loc[[]]
    Out[10]: Series([], dtype: float64)
    
    In [10]: 
    
    In [11]: data.loc[['b','d']]
    Out[11]: 
    b 1 -0.621072
    2 -0.200051
    3 -0.812091
    d 2 -0.646778
    3 1.622014
    dtype: float64
    

    有时甚至还可以在“内层”中进行选取

    In [12]: data[:2]
    Out[12]: 
    a 1 -1.155262
    2 1.141384
    dtype: float64
    
    In [13]: data[:,2]
    Out[13]: 
    a 1.141384
    b -0.200051
    c 0.293709
    d -0.646778
    dtype: float64
    

    层次化索引在数据重塑和基于分组的操作(如透视表生成)中扮演着重要的角色。比如说,这段数据可以通过其unstack方法被重新安排到一个DataFrame中

    In [14]: data.unstack()
    Out[14]: 
    1 2 3
    a -1.155262 1.141384 -1.046202
    b -0.621072 -0.200051 -0.812091
    c 1.762207 0.293709 NaN
    d NaN -0.646778 1.622014
    

    unstack的逆运算是stack

    In [15]: data.unstack().stack()
    Out[15]: 
    a 1 -1.155262
    2 1.141384
    3 -1.046202
    b 1 -0.621072
    2 -0.200051
    3 -0.812091
    c 1 1.762207
    2 0.293709
    d 2 -0.646778
    3 1.622014
    dtype: float64
    

    对于一个DataFrame,每条轴都可以有分层索引

    In [16]: frame = DataFrame(np.arange(12).reshape((4, 3)),
        ...: index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
        ...: columns=[['Ohio', 'Ohio', 'Colorado'],
        ...: ['Green', 'Red', 'Green']])
    
    In [17]: frame
    Out[17]: 
    Ohio Colorado
    Green Red Green
    a 1 0 1 2
    2 3 4 5
    b 1 6 7 8
    2 9 10 11
    
    In [18]: frame.index.names=['key1','key2']
    
    In [19]: frame.columns.names=['state','color']
    
    In [20]: frame
    Out[20]: 
    state Ohio Colorado
    color Green Red Green
    key1 key2 
    a 1 0 1 2
    2 3 4 5
    b 1 6 7 8
    2 9 10 11
    
    In [21]: frame['Ohio']
    Out[21]: 
    color Green Red
    key1 key2 
    a 1 0 1
    2 3 4
    b 1 6 7
    2 9 10
    

    重排分级顺序
    有时,你需要重新调整某条轴上各级别的顺序,或根据指定级别上的值对数据进行排序。swaplevel接受两个级别编号或名称,并返回一个互换了级别的新对象(但数据不会发生变化)

    In [23]: frame.swaplevel('key1', 'key2')
    Out[23]: 
    state Ohio Colorado
    color Green Red Green
    key2 key1 
    1 a 0 1 2
    2 a 3 4 5
    1 b 6 7 8
    2 b 9 10 11
    

    sortlevel则根据单个级别中的值对数据进行排序(稳定的)。交换级别时,常常也会用到sortlevel,这样最终结果就是有序的

    In [24]: frame.sortlevel(1)
    Out[24]: 
    state Ohio Colorado
    color Green Red Green
    key1 key2 
    a 1 0 1 2
    b 1 6 7 8
    a 2 3 4 5
    b 2 9 10 11
    
    In [25]: frame.swaplevel(0, 1)
    Out[25]: 
    state Ohio Colorado
    color Green Red Green
    key2 key1 
    1 a 0 1 2
    2 a 3 4 5
    1 b 6 7 8
    2 b 9 10 11
    
    In [26]: frame.swaplevel(0, 1).sortlevel(0)
    Out[26]: 
    state Ohio Colorado
    color Green Red Green
    key2 key1 
    1 a 0 1 2
    b 6 7 8
    2 a 3 4 5
    b 9 10 11
    

    注意:在层次化索引的对象上,如果索引是按字典方式从外到内排序(即调用sortlevel(0)或sort_index()的结果),数据选取操作的性能要好很多。

    根据级别汇总统计
    许多对DataFrame和Series的描述和汇总统计都有一个level选项,它用于指定在某条轴上求和的级别。再以上面那个DataFrame为例,我们可以根据行或列上的级别来进行求和。

    In [27]: frame
    Out[27]: 
    state Ohio Colorado
    color Green Red Green
    key1 key2 
    a 1 0 1 2
    2 3 4 5
    b 1 6 7 8
    2 9 10 11
    
    In [28]: frame.sum(level='key2')
    Out[28]: 
    state Ohio Colorado
    color Green Red Green
    key2 
    1 6 8 10
    2 12 14 16
    
    In [29]: frame.sum(level='color', axis=1)
    Out[29]: 
    color Green Red
    key1 key2 
    a 1 2 1
    2 8 4
    b 1 14 7
    2 20 10
    

    使用DataFrame的列
    人们经常想要将DataFrame的一个或多个列当做行索引来用,或者可能希望将行索引变成DataFrame的列。

    In [30]: frame = DataFrame({'a': range(7), 'b': range(7, 0, -1),
        ...: 'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'],
        ...: 'd': [0, 1, 2, 0, 1, 2, 3]})
    
    In [31]: frame
    Out[31]: 
    a b c d
    0 0 7 one 0
    1 1 6 one 1
    2 2 5 one 2
    3 3 4 two 0
    4 4 3 two 1
    5 5 2 two 2
    6 6 1 two 3
    

    DataFrame的set_index函数会将其一个或多个列转换为行索引,并创建一个新的DataFrame

    In [32]: frame2=frame.set_index(['c','d'])
    
    In [33]: frame2
    Out[33]: 
    a b
    c d 
    one 0 0 7
    1 1 6
    2 2 5
    two 0 3 4
    1 4 3
    2 5 2
    3 6 1
    

    默认情况下,那些列会从DataFrame中移除,但也可以将其保留下来

    In [34]: frame.set_index(['c','d'],drop=False)
    Out[34]: 
    a b c d
    c d 
    one 0 0 7 one 0
    1 1 6 one 1
    2 2 5 one 2
    two 0 3 4 two 0
    1 4 3 two 1
    2 5 2 two 2
    3 6 1 two 3
    

    reset_index的功能跟set_index刚好相反,层次化索引的级别会被转移到列里面

    In [35]: frame2.reset_index()
    Out[35]: 
    c d a b
    0 one 0 0 7
    1 one 1 1 6
    2 one 2 2 5
    3 two 0 3 4
    4 two 1 4 3
    5 two 2 5 2
    6 two 3 6 1
    

    接下来练习下一章节

    相关文章

      网友评论

          本文标题:《利用Python进行数据分析》第五章 pandas的数据汇总与

          本文链接:https://www.haomeiwen.com/subject/oustwxtx.html