Pandas数据处理2:缺省值与多级索引

import numpy as np 
import pandas as pd 
#处理缺失值
#标签的方法:None和NaN
vals1 = np.array([1, None, 3, 4])
vals1
#object型的numpy数组认为对象是python对象,进行快速操作时会更慢
array([1, None, 3, 4], dtype=object)
#使用NaN:和之前的 object 类型数组不同,这个数组会被编译成 C 代码从而实现快速操作。你可以把 NaN 看作是一个数据类病毒——它会将与它接触过的数据同化。
vals2 = np.array([1, np.nan, 3, 4]) 
print(vals2.dtype)
print(1 + np.nan)
float64
nan
#NumPy 也提供了一些特殊的累计函数,它们可以忽略缺失值的影响
np.nansum(vals2), np.nanmin(vals2), np.nanmax(vals2)
#谨记,NaN 是一种特殊的浮点数,不是整数、字符串以及其他数据类型。
(8.0, 1.0, 4.0)
# isnull()  创建一个布尔类型的掩码标签缺失值。
# notnull() 与 isnull() 操作相反。
# dropna()  返回一个剔除缺失值的数据。
# fillna()  返回一个填充了缺失值的数据副本。
data = pd.Series([1, np.nan, 'hello', None])
print(data)
print(data.isnull())
print(data[data.notnull()])
print(data.dropna())
print(data.fillna('!!'))
0        1
1      NaN
2    hello
3     None
dtype: object
0    False
1     True
2    False
3     True
dtype: bool
0        1
2    hello
dtype: object
0        1
2    hello
dtype: object
0        1
1       !!
2    hello
3       !!
dtype: object
#dataframe的剔除缺失值
df = pd.DataFrame([ [1, np.nan, 2], 
                    [2, 3, 5], 
                    [np.nan, 4, 6]])
print(df.dropna())#默认情况下,dropna() 会剔除任何包含缺失值的整行数据
print(df.dropna(axis=1))#可以设置按不同的坐标轴剔除缺失值,比如 axis=1(或 axis='columns')会剔除任何包含缺失值的整列数据
print(df.dropna(how='all'))#可以设置 how='all',这样就只会剔除全部是缺失值的行或列了;默认是how='any'
print(df.dropna(axis='rows', thresh=3))#通过 thresh 参数设置行或列中非缺失值的最小数量
     0    1  2
1  2.0  3.0  5
   2
0  2
1  5
2  6
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6
     0    1  2
1  2.0  3.0  5
#填充缺失值
#可以用缺失值前面的有效值来从前往后填充
data = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))
print(data.fillna(method='ffill'))
#也可以用缺失值后面的有效值来从后往前填充
print(data.fillna(method='bfill'))
#DataFrame 的操作方法与 Series 类似,只是在填充时需要设置坐标轴参数 axis
print(df.fillna(method='ffill',axis=1))
a    1.0
b    1.0
c    2.0
d    2.0
e    3.0
dtype: float64
a    1.0
b    2.0
c    2.0
d    3.0
e    3.0
dtype: float64
     0    1    2
0  1.0  1.0  2.0
1  2.0  3.0  5.0
2  NaN  4.0  6.0
#pandas多级索引
#笨办法
index = [('California', 2000), ('California', 2010), ('New York', 2000), ('New York', 2010), ('Texas', 2000),('Texas', 2010)] 
populations = [33871648, 37253956, 18976457, 19378102, 20851820, 25145561] 
pop = pd.Series(populations, index=index)

#用元组创建一个多级索引
index = pd.MultiIndex.from_tuples(index)
#如果将前面创建的 pop 的索引重置(reindex)为 MultiIndex,就会看到层级索引
pop = pop.reindex(index)
print(pop)
#现在可以直接用第二个索引获取 2010 年的全部数据,与 Pandas 的切片查询用法一致
print(pop[:,2010])
California  2000    33871648
            2010    37253956
New York    2000    18976457
            2010    19378102
Texas       2000    20851820
            2010    25145561
dtype: int64
California    37253956
New York      19378102
Texas         25145561
dtype: int64
#unstack() 方法可以快速将一个多级索引的Series 转化为普通索引的 DataFrame
#也有 stack() 方法实现相反的效果
pop_df = pop.unstack()
print(pop_df)
print(pop_df.stack())
                2000      2010
California  33871648  37253956
New York    18976457  19378102
Texas       20851820  25145561
California  2000    33871648
            2010    37253956
New York    2000    18976457
            2010    19378102
Texas       2000    20851820
            2010    25145561
dtype: int64
#对于这种带有 MultiIndex 的对象,增加一列就像 DataFrame 的操作一样简单
#假如要增加一列显示每一年各州的人口统计指标(例如 18岁以下的人口)
pop_df = pd.DataFrame({'total': pop, 
                        'under18': [9267089, 9284094, 
                                    4687374, 4318033, 
                                    5906301, 6879014]})
print(pop_df.stack())
print(pop_df)
California  2000  total      33871648
                  under18     9267089
            2010  total      37253956
                  under18     9284094
New York    2000  total      18976457
                  under18     4687374
            2010  total      19378102
                  under18     4318033
Texas       2000  total      20851820
                  under18     5906301
            2010  total      25145561
                  under18     6879014
dtype: int64
                    total  under18
California 2000  33871648  9267089
           2010  37253956  9284094
New York   2000  18976457  4687374
           2010  19378102  4318033
Texas      2000  20851820  5906301
           2010  25145561  6879014
#通用函数和其他功能也同样适用于层级索引。例如我们可以计算上面数据中 18 岁以下的人口占总人口的比例
f_u18 = pop_df['under18'] / pop_df['total'] 
print(f_u18.unstack())
                2000      2010
California  0.273594  0.249211
New York    0.247010  0.222831
Texas       0.283251  0.273568
#创建多级索引
#创建多级索引最直接的办法就是将 index 参数设置为至少二维的索引数组
df = pd.DataFrame(np.random.rand(4, 2), index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]], columns=['data1', 'data2'])
print(df)
#如果你把将元组作为键的字典传递给 Pandas, Pandas 也会默认转换为 MultiIndex
data = {('California', 2000): 33871648, 
    ('California', 2010): 37253956, 
    ('Texas', 2000): 20851820, 
    ('Texas', 2010): 25145561, 
    ('New York', 2000): 18976457, 
    ('New York', 2010): 19378102} 
print(pd.Series(data))
        data1     data2
a 1  0.258407  0.651764
  2  0.885183  0.387104
b 1  0.350668  0.037229
  2  0.654967  0.620773
California  2000    33871648
            2010    37253956
Texas       2000    20851820
            2010    25145561
New York    2000    18976457
            2010    19378102
dtype: int64
#显式创建多级索引
#通过一个有不同等级的若干简单数组组成的列表来构建 MultiIndex
print(pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'], [1, 2, 1, 2]]))
#也可以通过包含多个索引值的元组构成的列表创建 MultiIndex
print(pd.MultiIndex.from_tuples([('a', 1), ('a', 2), ('b', 1), ('b', 2)]))
#还可以用两个索引的笛卡尔积(Cartesian product)创建 MultiIndex
print(pd.MultiIndex.from_product([['a','b'],[1,2]]))
#还可以直接提供 levels(包含每个等级的索引值列表的列表)和 labels(包含每个索引值标签列表的列表)创建 MultiIndex
#!这个现在的版本不能用了
# print( pd.MultiIndex(levels=[['a', 'b'], [1, 2]],  labels=[[0, 0, 1, 1], [0, 1, 0, 1]]))  
MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2)],
           )
MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2)],
           )
MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2)],
           )
#在创建 Series 或 DataFrame 时,可以将这些对象作为 index 参数,或者通过 reindex 方法更新 Series 或 DataFrame 的索引。
#可以在前面任何一个 MultiIndex构造器中通过 names 参数设置等级名称,也可以在创建之后通过索引的 names 属性来修改名称:
print(df)
df.index.names = ['n1','n2']
print(df)
        data1     data2
a 1  0.258407  0.651764
  2  0.885183  0.387104
b 1  0.350668  0.037229
  2  0.654967  0.620773
          data1     data2
n1 n2                    
a  1   0.258407  0.651764
   2   0.885183  0.387104
b  1   0.350668  0.037229
   2   0.654967  0.620773
#多级列索引同理,一个例子:
# 多级行列索引
index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]], names=['year', 'visit']) 
columns = pd.MultiIndex.from_product([['Bob', 'Guido', 'Sue'], ['HR', 'Temp']], names=['subject', 'type']) 
# 模拟数据
data = np.round(np.random.randn(4, 6), 1) 
data[:, ::2] *= 10 
data += 37 
# 创建DataFrame 
health_data = pd.DataFrame(data, index=index, columns=columns)
print(health_data)
subject      Bob       Guido         Sue      
type          HR  Temp    HR  Temp    HR  Temp
year visit                                    
2013 1      25.0  36.7  40.0  38.5  40.0  38.5
     2      32.0  35.0  42.0  37.8  47.0  36.1
2014 1      37.0  35.3  48.0  37.4  40.0  37.0
     2      34.0  37.0  42.0  36.3  46.0  36.9
#可以在列索引的第一级查询姓名,从而获取包含一个人(例如 Guido)全部检查信息的 DataFrame
print(health_data['Bob'])
type          HR  Temp
year visit            
2013 1      25.0  36.7
     2      32.0  35.0
2014 1      37.0  35.3
     2      34.0  37.0
#series多级索引的取值和切片
print(pop)
print(pop['New York',2010])
print(pop['New York'])
print(pop[:,2000])
California  2000    33871648
            2010    37253956
New York    2000    18976457
            2010    19378102
Texas       2000    20851820
            2010    25145561
dtype: int64
19378102
2000    18976457
2010    19378102
dtype: int64
California    33871648
New York      18976457
Texas         20851820
dtype: int64
#dataframe多级索引的取值和切片
print(health_data)
#由于 DataFrame 的基本索引是列索引,因此 Series 中多级索引的用法到了 DataFrame 中就应用在列上了
print(health_data['Guido', 'HR'])
print(health_data.loc[2013,1])
print(health_data.iloc[:2, :2])
#虽然这些索引器将多维数据当作二维数据处理,但是在 loc 和 iloc 中可以传递多个层级的索引元组,例如:
print(health_data.loc[:, ('Bob', 'HR')])
subject      Bob       Guido         Sue      
type          HR  Temp    HR  Temp    HR  Temp
year visit                                    
2013 1      25.0  36.7  40.0  38.5  40.0  38.5
     2      32.0  35.0  42.0  37.8  47.0  36.1
2014 1      37.0  35.3  48.0  37.4  40.0  37.0
     2      34.0  37.0  42.0  36.3  46.0  36.9
year  visit
2013  1        40.0
      2        42.0
2014  1        48.0
      2        42.0
Name: (Guido, HR), dtype: float64
subject  type
Bob      HR      25.0
         Temp    36.7
Guido    HR      40.0
         Temp    38.5
Sue      HR      40.0
         Temp    38.5
Name: (2013, 1), dtype: float64
subject      Bob      
type          HR  Temp
year visit            
2013 1      25.0  36.7
     2      32.0  35.0
year  visit
2013  1        25.0
      2        32.0
2014  1        37.0
      2        34.0
Name: (Bob, HR), dtype: float64
#使用pandas的IndexSlice 对象构建切片
print(health_data)
idx = pd.IndexSlice 
print(health_data.loc[idx[:, 1], idx[:, 'HR']])
subject      Bob       Guido         Sue      
type          HR  Temp    HR  Temp    HR  Temp
year visit                                    
2013 1      25.0  36.7  40.0  38.5  40.0  38.5
     2      32.0  35.0  42.0  37.8  47.0  36.1
2014 1      37.0  35.3  48.0  37.4  40.0  37.0
     2      34.0  37.0  42.0  36.3  46.0  36.9
subject      Bob Guido   Sue
type          HR    HR    HR
year visit                  
2013 1      25.0  40.0  40.0
2014 1      37.0  48.0  40.0
#局部切片和许多其他相似的操作都要求 MultiIndex 的各级索引是有序的(即按照字典顺序由 A 至 Z)。为此,Pandas 提供了许多便捷操作完成排序,如 sort_index() 和 sortlevel() 方法。
index = pd.MultiIndex.from_product([['a', 'c', 'b'], [1, 2]]) 
data = pd.Series(np.random.rand(6), index=index) 
data.index.names = ['char', 'int']
print(data)
#data['a': 'b']   如果MultiIndex 不是有序的索引,那么大多数切片操作都会失败。
data = data.sort_index()
print(data)
char  int
a     1      0.567379
      2      0.095427
c     1      0.958445
      2      0.151906
b     1      0.543022
      2      0.908223
dtype: float64
char  int
a     1      0.567379
      2      0.095427
b     1      0.543022
      2      0.908223
c     1      0.958445
      2      0.151906
dtype: float64
#   重建索引
# 可以将一个多级索引数据集转换成简单的二维形式,可以通过 level 参数设置转换的索引层级
print(pop)
print(pop.unstack(level=1))
California  2000    33871648
            2010    37253956
New York    2000    18976457
            2010    19378102
Texas       2000    20851820
            2010    25145561
dtype: int64
                2000      2010
California  33871648  37253956
New York    18976457  19378102
Texas       20851820  25145561
pop.index.names= ['state','year']
print(pop)
pop_flat = pop.reset_index(name='population')
print(pop_flat)
#通过 DataFrame 的 set_index 方法实现,返回结果就会是一个带多级索引的 DataFrame
#在解决实际问题的时候,如果能将类似这样的原始输入数据的列直接转换成 MultiIndex,会很有帮助
print( pop_flat.set_index(['state', 'year']))
state       year
California  2000    33871648
            2010    37253956
New York    2000    18976457
            2010    19378102
Texas       2000    20851820
            2010    25145561
dtype: int64
        state  year  population
0  California  2000    33871648
1  California  2010    37253956
2    New York  2000    18976457
3    New York  2010    19378102
4       Texas  2000    20851820
5       Texas  2010    25145561
                 population
state      year            
California 2000    33871648
           2010    37253956
New York   2000    18976457
           2010    19378102
Texas      2000    20851820
           2010    25145561
#多级索引的数据累计方法
#可以设置参数 level 实现对数据子集的累计操作
print(health_data)
data_mean = health_data.mean(level='year')  #一年各项指标的均值
print(data_mean)
#如果再设置 axis 参数,就可以对列索引进行类似的累计操作了
print(data_mean.mean(level=1,axis=1))
subject      Bob       Guido         Sue      
type          HR  Temp    HR  Temp    HR  Temp
year visit                                    
2013 1      25.0  36.7  40.0  38.5  40.0  38.5
     2      32.0  35.0  42.0  37.8  47.0  36.1
2014 1      37.0  35.3  48.0  37.4  40.0  37.0
     2      34.0  37.0  42.0  36.3  46.0  36.9
subject   Bob        Guido          Sue       
type       HR   Temp    HR   Temp    HR   Temp
year                                          
2013     28.5  35.85  41.0  38.15  43.5  37.30
2014     35.5  36.15  45.0  36.85  43.0  36.95
type         HR   Temp
year                  
2013  37.666667  37.10
2014  41.166667  36.65

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值