02.数据分析之pandas的使用

2.pandas的使用

一、pandas简介

pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

Pandas最初被作为金融数据分析工具而开发出来,因此,pandas为时间序列分析提供了很好的支持。 Pandas的名称来自于面板数据(panel data)和python数据分析(data analysis)

二、Series(序列)使用

1.创建Series
from pandas import Series
import numpy as np

# 类似一维数组


# 1.使用列表创建:
s = Series(data = [94, 54, 80])  # 使用列表创建 只给定values, 默认index
print(type(s))  # Series

s = Series(data = [94, 54, 80], index=['语文','数学', '英语'])  # 给定values和index
print(s)  # 打印对象,重写了__str__()方法
'''
语文    94
数学    54
英语    80
dtype: int64
'''


# 2.使用ndarray创建
nd = np.random.randint(1, 10, size=5)  
s = Series(data=nd)
print(s)





# 3.使用字典创建
s = Series({'语文':90, '数学':88, '英语':89})  # 其索引为keys
print(s)
print(s.index)  # Index(['语文', '数学', '英语'], dtype='object')
# '''
# 语文    90
# 数学    88
# 英语    89
# dtype: int64
# '''


使用列表、字典与ndarray创建的区别:

由ndarray创建的是引用,而不是副本。对Series元素的改变也会改变原来的ndarray对象中的元素。(字典、列表没有这种情况)
2.Series的属性
from pandas import Series

# 二、Series的属性

s = Series({'语文':88, '数学':89, '英语':90})
print(s.index)  # Index(['语文', '数学', '英语'], dtype='object')  索引
print(s.values, type(s.values))  # [88 89 90]  ndarray  值域
print(s.shape)  # (3,)  一维,有三个元素
print(s.size)  # 3  元素的个数
3.Series的索引和切片
# 三、Series的索引和切片
from pandas import Series

# 索引
s = Series({'语文':88, '数学':89, '英语':90})

# (1)显式索引的两种写法
print(s['英语'],)  # 90  直接写中括号
print(s.loc['语文'])  # 88 第二种,使用loc[], location 推荐写法.



# (2) 隐式索引:
# - 使用整数作为索引值
# - 使用.iloc[](推荐)
print(s[0])  # 88
print(s.iloc[1])  # 89


# 使用loc与iloc主要是为了当Series的index为0、1..时的发生的歧义



# (3) 使用get(),当元素不存在的时候返回None
s.get('语文')   # 88
s.get('语文1')   # None


# (4)特殊:
# 索引时再加一个中括号,返回Series类型
print(type(s.loc[['语文']]))  # <class 'pandas.core.series.Series'>




print('\n******切片******\n')
# 切片
# (1)显式索引切片,  # 全闭区间
print(s['语文':'数学'])
print(s.loc['语文':'数学'])

# '''
# 语文    88
# 数学    89
# dtype: int64
# '''

print('**********')
# (2) 隐式索引切片:# 左闭右开
print(s[0:2])  # 88
print(s.iloc[0:2])  # 89

# 语文    88
# 数学    89
# dtype: int64
4.Series 常用方法
# 四、Series 常用方法
import pandas as pd
from pandas import Series

s = Series({'语文':88, '数学':89, '英语':90})
#(1)  获取前n个,默认前5行
print(s.head(2))

#(2) 获取后n个,默认后5行
print(s.tail(2))


# 当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况
s = Series({'语文':88, '数学':89, '英语':90, '体育':None})

pd.isnull(s)  # 判断values是不是NAN,返回Series, values为True或False
s.isnull()    # 同上

pd.notnull(s) # 判断values不是nan,返回Series
s.notnull()  # 同上

'''
语文    False
数学    False
英语    False
体育     True
dtype: bool
'''
5.Series 增加删除修改元素
# 五、Series 增加删除修改元素
s = Series({'语文':88, '数学':89, '英语':90})
s.loc['语文'] = 90  # 修改元素

a = s.pop('英语')   # 删除元素
print(a)  # 90

s = s.append(Series({'py':80})) # 增加元素,需要另一个series
print(s)
6.Series的运算
# 六、Series的运算
# 1)Series与数字和字符串的运算
s = Series({'语文':'88', '数学':'89', '英语':'90'})
s+'1'   # 所有values都拼接,数字的话都加

# 2)Series之间的运算
# 在运算中自动对齐不同索引的数据
# 如果索引不对应,则补NaN
# Series没有广播机制 Series根据相同的索引进行运算索引不同补NaN

s1 = Series({'语文':88, '数学':89, '英语':90})
s2 = Series({'语文':88, '数学':89, 'py':90})
s1 + s2

'''
py      NaN
数学    178.0
英语      NaN
语文    176.0
dtype: float64

'''



s1 = Series({'语文':88, '数学':89, '英语':90})
s2 = Series({'语文':88, '数学':89, 'py':90})
s1.add(s2, fill_value=0)  # 保留所有的value,则需要使用.add()函数, fill_value给定填充值

'''
py     92.0
数学    178.0
英语     92.0
语文    176.0
dtype: float64
'''

三、DataFrame使用

1.创建DataFrame
from pandas import DataFrame
import numpy as np
# DataFrame可以看做是【由Series组成的字典】
# 其初衷是将Series的使用场景从一维拓展到多维。
# DataFrame既有行索引,也有列索引。

#  创建DataFrame, 推荐使用
index = ['张三', '李四', '王五', '赵六']
columns = ['语文', '数学', '英语']
data = np.random.randint(0, 150, size=(4,3,))
df = DataFrame(data=data, index=index, columns=columns)
                         
print(df, type(df))  # DataFrame
'''
     语文  数学   英语
张三  119  97   25
李四   72  65   52
王五  112  87  101
赵六  142  85  133 

<class 'pandas.core.frame.DataFrame'>

'''

# 字典创建DataFrame, 字典的key是列索引
df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                '数学':  np.random.randint(0,150, size=4), 
                '英语':  np.random.randint(0,150, size=4), 
                'python':  np.random.randint(0,150, size=4)}, 
               index = ['张三', '李四', '王五', '赵六'])
# df.index = ['张三', '李四', '王五', '赵六']
print(df, type(df)) 

'''
  语文   数学   英语  python
张三    6   13  121       3
李四    0   73   36     109
王五  127  135    4       7
赵六   94  126  146     139 

<class 'pandas.core.frame.DataFrame'>
'''
2.1.DataFrame的属性
# DataFrame的属性
df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                '数学':  np.random.randint(0,150, size=4), 
                '英语':  np.random.randint(0,150, size=4), 
                'python':  np.random.randint(0,150, size=4)}, 
               index = ['张三', '李四', '王五', '赵六'])


print(df.index) # 行索引  # Index(['张三', '李四', '王五', '赵六'], dtype='object')
print(df.columns) # 列索引 # Index(['语文', '数学', '英语', 'python'], dtype='object')
print(df.values)  # 值域
'''
[[  6  20 113  89]
 [ 46  25  11 133]
 [ 12  74 123  55]
 [  0 142 121  62]]
'''
print(df.shape)  # (4, 4)
2.2.DataFrame的增删改
index = ['张三', '李四', '王五', '赵六']
columns = ['语文', '数学', '英语']
data = np.random.randint(0, 150, size=(4,3,))
df = pd.DataFrame(data=data, index=index, columns=columns)

# 增加行
df.loc['田七'] = [78, 88, 90]
df

# 增加列
df['python'] = [88, 76, 90, 88]
df


# 删除行
df.drop('田七', inplace=True)
df

# 删除列
df.drop('python', axis=1, inplace=True)
df

# 改具体某个值
df.loc['张三', '英语'] = 100
df

# 当给某一列赋值给某变量时,如果后期需要修改这个变量的值而且要影响原dataframe,要使用深拷贝copy
data = df[['英语']].copy()
data['英语'] = data['英语'] + 1
df
3.DataFrame的索引
# DataFrame的索引与切片
(1) 对列进行索引
 - 通过类似字典的方式
 - 通过属性的方式
 可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,
 且name属性也已经设置好了,就是相应的列名

    df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                    '数学':  np.random.randint(0,150, size=4), 
                    '英语':  np.random.randint(0,150, size=4), 
                    'python':  np.random.randint(0,150, size=4)}, 
                   index = ['张三', '李四', '王五', '赵六'])

    print(df['语文'], type(df['语文']))  # Series
    '''
    张三    42
    李四    44
    王五    23
    赵六    13
    Name: 语文, dtype: int32 

    <class 'pandas.core.series.Series'>
    '''

    print(df[['语文', '数学']], type(df[['语文']]))  # 再加一层中括号,变为DataFrame 
    '''
       语文   数学
    张三  42  139
    李四  44   80
    王五  23   35
    赵六  13   21 

    <class 'pandas.core.frame.DataFrame'>
    '''




	df['理综'] = np.random.randint(0,300, size=4)  # 新增一列



(2) 对行进行索引
    - 使用.loc[]加index来进行行索引
    - 使用.iloc[]加整数来进行行索引
     同样返回一个Series,index为原来的columns。

    df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                    '数学':  np.random.randint(0,150, size=4), 
                    '英语':  np.random.randint(0,150, size=4), 
                    'python':  np.random.randint(0,150, size=4)}, 
                    index = ['张三', '李四', '王五', '赵六'])

    # 显示行索引
    print(df.loc['李四'], type(df.loc['李四']))  # 只能单个

    '''
    语文         56
    数学        102
    英语        106
    python     94
    Name: 李四, dtype: int32 <class 'pandas.core.series.Series'>
    '''


    print(df.loc[['张三','李四']], type(df.loc[['张三','李四']]))  # 可以多个

    '''
      语文  数学   英语  python
    张三    9  78  137      66
    李四  119  17   48      50 

    <class 'pandas.core.frame.DataFrame'>
    '''

    # 隐式行索引
    print(df.iloc[0], type(df.iloc[0]))
    '''
    语文        125
    数学        143
    英语        117
    python    126
    Name: 张三, dtype: int32 

    <class 'pandas.core.series.Series'>
    '''

    print(df.iloc[[0,2]], type(df.iloc[[0,2]]))

    '''
     语文   数学   英语  python
    张三  125  143  117     126
    王五   48   36   52      93 

    <class 'pandas.core.frame.DataFrame'>
    '''

    df.loc['田七'] = np.random.randint(0,150, size=4)  # 新增一行


    
(3) 对元素索引的方法
- 使用列索引
- 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]] 里面的[3,3]看做一个参数)
- 使用values属性(二维numpy数组)
    df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                    '数学':  np.random.randint(0,150, size=4), 
                    '英语':  np.random.randint(0,150, size=4), 
                    'python':  np.random.randint(0,150, size=4)}, 
                   index = ['张三', '李四', '王五', '赵六'])

    print(df)
    '''
         语文   数学   英语  python
    张三   49   57    4      41
    李四  120  135  110      75
    王五  120   41  148      91
    赵六  128  129   40       5
    '''


    print(df['语文'].loc['张三'])  # 49 先列索引,返回Series, 再索引到具体某个人
    print(df['语文']['张三'])   #  49 同上


    print(df.loc['王五'].loc['数学']) # 41 先行索引,返回Series, 再索引到具体某科目
    print(df.loc['王五']['数学'])  # 41 同上


    # 优化写法  推荐写法 
    print(df.loc['王五', '数学'])  # 41 具体定位
    display(df.loc[['张三'], ['数学']])  #  返回dataframe

4.DataFrame的切片
(1) 行切片
	
    
    1.直接使用中括号对DataFrame
      进行切片的时候,执行的 是行切片. print(df['张三':'李四'])
    2.使用显式索引进行行切片.         print(df.loc['张三': '王五'])
    3.使用隐式索引进行行切片.  	  print(df.iloc[1:3])

    df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                    '数学':  np.random.randint(0,150, size=4), 
                    '英语':  np.random.randint(0,150, size=4), 
                    'python':  np.random.randint(0,150, size=4)}, 
                   index = ['张三', '李四', '王五', '赵六'])

    print(df)
    '''
     	语文   数学   英语  python
        张三  105   68  117     118
        李四  119   74  106      34
        王五   20   94   86      60
        赵六   98  140   37       8
    '''


    print(df['张三':'李四'])  # 直接使用中括号对DataFrame进行切片的时候,执行的是行切片.
    '''
     	语文  数学   英语  python
        张三  105  68  117     118
        李四  119  74  106      34
    '''
    
    print(df.loc['张三':'王五'])
    '''
         语文   数学  英语  python
         张三   20  101  79     142
         李四  103   16  90     110
         王五   95  121  47      32
    '''
    
    print(df.iloc[1:3])
    
    
(2) 列切片:
    1.使用显式索引进行列切片.    print(df.loc[:, '语文':'数学'])
    2.对列进行隐式切片          print(df.iloc[:, 1:3])
    
    print(df.loc[:, '语文':'数学'])
    '''
          语文  数学
    张三  126  21
    李四  135  67
    王五   48  24
    赵六   67  21
    '''
    
    print(df.iloc[:, 1:3])
    
    '''
         数学   英语
    张三   51   36
    李四  147   21
    王五   59  130
    赵六  146  125
    '''
    
总结:
    1, 行索引永远用.loc[]
    2, 列索引用于用[]
    3, 索引元素的时候,先找行再找列,使用.loc[index, column]
    4, 切片的时候,直接使用中括号是对行切片 , 对列进行切片也需要先从行开始 .loc[:, column: column]    
5.DataFrame的运算
(1)DataFrame之间的运算

    同Series一样:
    在运算中自动对齐不同索引的数据
    如果索引不对应,则补NaN

        df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                        '数学':  np.random.randint(0,150, size=4), 
                        '英语':  np.random.randint(0,150, size=4), 
                        'python':  np.random.randint(0,150, size=4)}, 
                       index = ['张三', '李四', '王五', '赵六'])

        df2 = df.copy()

        df + df2  # 如果索引不对应,则补NaN, NaN与任何数相加都得NaN
    
    
   如果要保留原始数据则使用add()、sub()、mul()、div()  --加减乘除
    df.add(df2, fill_value=0)  # fill_value 索引不对称, 填充02) Series与DataFrame之间的运算

【重要】
    使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。
    (类似于numpy中二维数组与一维数组的运算,但可能出现NaN)
    
    df = DataFrame({'语文': np.random.randint(0,150, size=4), 
                    '数学':  np.random.randint(0,150, size=4), 
                    '英语':  np.random.randint(0,150, size=4), 
                    'python':  np.random.randint(0,150, size=4)}, 
                   index = ['张三', '李四', '王五', '赵六'])
    
    
    s = Series(index=['语文', '数学', '英语', 'python', '文综'], 
               data=np.random.randint(0,150, size=(5)))
    
    df + s  # 以行为单位操作,对所有行都有效
    
    
    
    
    s2 = Series(index=['张三', '李四', '王五', '赵六', '田七'], 
                data=np.random.randint(0,150, size=(5)))
    
    df.add(s, axis='columns')  # 以行为单位操作,对所有行都有效
    df.add(s, axis='index')  # 以列为单位操作,对所有列都有效
    # 不能有fill_values
    总结: DataFrame和Series进行运算的时候,默认是按照DataFrame的列索引进行操作, 
          列索引一致才进行运算,列索引不一致补NaN.
    可以通过pandas封装的运算函数的axis来修改操作的方向.
6.DataFrame处理丢失数据
(1).pandas中的None与NaN【pandas中None与np.nan都视作np.nan】

    df = DataFrame({'语文': np.random.randint(0,150, size=3), 
                    '数学':  np.random.randint(0,150, size=3), 
                    '英语':  np.random.randint(0,150, size=3), 
                    'python':  np.random.randint(0,150, size=3)}, 
                   index = ['张三', '李四', '王五'])

    df.loc['张三', '数学'] = np.nan
    df.loc['李四', '英语'] = None

        '''
             	  语文   数学  英语  python
             张三   20  NAN  79     142
             李四  103   16  NAN     110
             王五   95  121  47      32
        '''

pandas中None与np.nan的操作:
    
1) 判断函数:

    (1).df.isnull()与 pd.isnull() 同样的效果
    # 作用:判断DataFrame中的每个元素是否为NAN, 是返回True, 否则返回False
    '''
         语文		数学	   英语	  python
    张三	False	True	False	False
    李四	False	False	True	False
    王五	False	False	False	False
    '''
    
    (2).df.notnull()与pd.notnull()同样的效果
    # 作用:判断DataFrame中的每个元素是否不为NAN, 是返回True, 否则返回False
    '''
         语文		数学		英语	  python
    张三	True	False	True	True
    李四	True	True	False	True
    王五	True	True	True	True
    '''
    
    (3)
    # 接和any和all, 判断行列是否有空数据.
    # 判断列是否有空数据
    df.isnull().any(axis=0)	
    df.isnull().any(axis=1)
    
2).过滤函数:

        df = DataFrame({'语文': np.random.randint(0,150, size=3), 
                        '数学':  np.random.randint(0,150, size=3), 
                        '英语':  np.random.randint(0,150, size=3), 
                        'python':  np.random.randint(0,150, size=3)}, 
                       index = ['张三', '李四', '王五'])

    df.loc['张三', '数学'] = np.nan
    df.loc['李四', '英语'] = None

        '''
             	  语文   数学  英语  python
             张三   20  NAN  79     142
             李四  103   16  NAN     110
             王五   95  121  47      32
        '''
        
    df.dropna(axis=0, how='any', subset=None, inplace=False)  # 用于删除含有空值的行或列

    # axis控制删除行还是列, axis=0表示删除行,
    # how控制怎么删, any表示只要有空删除. all全是空才删除. 默认any
    # subset 指定列索引子集,只判断子集的元素
    # inplace 是否改变原DataFrame, 默认不改变

    事例:
    (1) df.dropna(axis=0)
    '''
    	 语文	数学	  英语	python
	王五	147	40.0	95.0	41
    '''
    
    (2) df.dropna(axis=0, how='all', subset=['数学'])
      '''
              语文	数学	 英语	 python
        李四	87		5.0	  NaN  38
        王五	147		40.0  95.0 4
      '''
        
        
3).填充函数 df.fillna()
    df = DataFrame({'语文': np.random.randint(0,150, size=3), 
                    '数学':  np.random.randint(0,150, size=3), 
                    '英语':  np.random.randint(0,150, size=3), 
                    'python':  np.random.randint(0,150, size=3)}, 
                   index = ['张三', '李四', '王五'])

    df.loc['张三', '数学'] = np.nan
    df.loc['李四', '英语'] = None

   '''
   	  	语文   数学  英语  python
   张三   20  NAN  79     142
   李四  103   16  NAN     110
   王五   95  121  47      32
   '''

# 用指定的值指定的方式填充NAN
df.fillna(value=None, method=None, axis=None, inplace=False, limit=None)

# fillna有两个用法.
# 第一个用法: 用指定的值来填充.
(1) df.fillna(value=88)

   '''
   	  	语文   数学  英语  python
   张三   20  88  79     142
   李四  103   16  88     110
   王五   95  121  47      32
   '''
    
# 第二个用法, 用已有的值填充.
# method : {'backfill', 'bfill', 'pad', 'ffill', None}
# backfill bfill  -- 用后面的数据填充 
# pad, ffill      -- 用前面的数据填充   forward
# 前后关系要根据axis来定
# limit 限制连续填充的次数
df.fillna(axis=1, method='ffill') 
7.DataFrame多层索引
'''
1.创建多层索引的DataFrame的方式
隐式、显示
'''
# 1). 给索引index和columns参数传递两个或更多的数组

index = [['一班','一班','一班','二班','二班','二班',], ['张三','李四','王五','赵六','田七','黄八']]
columns = [['期中','期中','期中','期末','期末','期末'],['语文', '数学', '英语','语文', '数学', '英语']]
data = np.random.randint(0, 100, size=(6, 6))
df = DataFrame(index=index, columns=columns, data=data)
display(df)

# 2). 显示构造之数组pd.MultiIndex.from_arrays()
index = pd.MultiIndex.from_arrays([['一班','一班', '二班','二班'],['张三','李四','王五','赵六']])
columns= pd.MultiIndex.from_arrays([['期中','期中','期末','期末'],['语文', '数学','语文', '数学']]) 
data = np.random.randint(0, 100, size=(4, 4))
df2 = DataFrame(index=index, columns=columns, data=data)
display(df2)

# 3). 显示构造之元组pd.MultiIndex.from_arrays()
index = pd.MultiIndex.from_tuples([('一班', '张三'),('一班', '李四'),('二班', '王五'),('二班', '赵六')])
columns= pd.MultiIndex.from_tuples([('期中','语文'),('期中','数学'),('期末','语文'),('期末','数学')]) 
data = np.random.randint(0, 100, size=(4, 4))
df3 = DataFrame(index=index, columns=columns, data=data)
display(df3)

# 4).显示构造之元组pd.MultiIndex.from_product()
index = pd.MultiIndex.from_product([['一班', '二班'], ['张三', '李四', '王五']])
columns = pd.MultiIndex.from_product([['期中', '期末'], ['语文', '数学', '英语']])
data = np.random.randint(0, 150, size=(6,6))
df = DataFrame(index=index, columns=columns, data=data)
display(df)


'''
2.多层索引对象的索引

'''

index = pd.MultiIndex.from_tuples([('一班', '张三'),('一班', '李四'),('二班', '王五'),('二班', '赵六')])
columns= pd.MultiIndex.from_tuples([('期中','语文'),('期中','数学'),('期末','语文'),('期末','数学')]) 
data = np.random.randint(0, 100, size=(4, 4))
df3 = DataFrame(index=index, columns=columns, data=data)
display(df3)

'''
		  期中	 期末
		  语文 数学	语文 数学
一班	张三	94	21	74	9
	 李四	 57	 53	 9	 18
二班	王五	80	99	12	26
     赵六	 56	 60	 48	 75
'''


# (1)列索引
df['期中', '语文']  # 不推荐
display(df3.loc[:, ('期中', '语文')])  # 列显式索引  
display(type(df3.loc[:, ('期中', '语文')]))  # 返回Series
display(df3.iloc[:, [0]])   # 列隐式索引,   隐式索引只有一层


# (2)行索引
display(df3.loc[[('二班','赵六')]])  # 行显式索引, 加多一层[]返回dataframe
display(df3.iloc[[1]])   # # 行隐式索引, 加多一层[]返回dataframe

# (3)元素索引

display(df3.loc[('二班','王五'),('期末','语文')])  # 显式索引元素
df3.iloc[2, 2]  # 隐式索引元素
df3.iloc[[2], [2]]   


'''
3.多层索引对象切片操作
'''
# (1)列切片

display(df3.loc[:, '期中':'期中'])  # 列显式切片 , 不能再加小括号,列显式切片只能切一层
display(df3.loc[:, [('期中','语文')]]) 
display(df3.iloc[:, 0:1])   # 列隐式索引,   隐式索引只有一层


# (2)行切片
display(df3.loc['二班':'二班'])  # 行显式切片, 不能再加小括号,行显式切片只能切一层
display(df3.iloc[2:])        #  行隐式切片,


'''
4. 多层索引对象索引的栈(stack)
'''
# stack就是把列索引变成行索引. 
# unstack就是把行索引变成列索引

# df3.stack(level=-1, dropna=True)   # level 用于指定索引,默认倒数第一层
df3.stack()

# df3.unstack(level=-1, fill_value=None)   # fill_value用来填充空值的.
df3.unstack(fill_value=0)



'''
5. 多层索引对象聚合操作
'''
# df3.sum(axis=None, skipna=None, level=None,)  # 求和 
# df3.mean(axis=None, skipna=None, level=None,)  # 求平均
# df3.std(axis=None, skipna=None, level=None,) # 求标准差

# axis=0 ,表示对行进行聚合, axis=1, 表示对列进行聚合. 默认对行聚合
# level指定要保留哪一层索引.

display(df3.mean(level=0))

display(df3.sum(axis=1, level=0))
8.1.DataFrame的级联
'''
 1). 使用pd.concat()级联
'''
# 封装生成dataframe函数
def make_df(index, cols):
    df = DataFrame({col: [col + str(i) for i in index] for col in cols})
    df.index = index
    return df

df1 = make_df([1,2,3,4], list('ABCD'))
df2 = df1.copy()
display(df1, df2)


# pd.concat(objs, axis=0, join='outer', 
#           join_axes=None, ignore_index=False, 
#           keys=None, levels=None, 
#           names=None, verify_integrity=False, 
#           sort=None, copy=True)

# 1.axis来改变级联方向,  axis=0 行级联,axis=1 列级联 默认行级联
# 2.join级联方式,
#  外连接:补NaN(默认模式);
#  内连接:只连接匹配的项;  
#  连接指定轴 join_axes
# 2.ignore_index 忽略原有的索引,用0,1,2...重新编码
# 3.verify_integrity  索引是否能重复,默认值为False,
#   如果为True当创建相同的index时会抛出ValueError的异常
# 4.keys用于区分两个dataframe
# 5.join_axes可以指定根据那个轴来对齐数据, 如果是index,要配合axis=1 
display(pd.concat((df1, df2), axis=0))
display(pd.concat((df1, df2), axis=1))
display(pd.concat((df1, df2), axis=1, ignore_index=True))  # ignore_index 忽略原有的索引,用0,1,2...重新编码
# display(pd.concat((df1, df2), verify_integrity=True))
pd.concat([df1,df2],axis=1, join_axes=[df2.index])



'''
2).不匹配级联
不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致

有4种连接方式:
外连接:补NaN(默认模式)
内连接:只连接匹配的项
左连接: 右边可能出现NaN
右连接: 左边可能出现NaN
'''
df1 = make_df([1,2,3,4], list('ABCD'))
df2 = make_df([2,3,4,5], list('BCDE'))

# 只输出匹配的数据
pd.concat((df1, df2), axis=1, sort=True, join='inner')


连接指定轴 join_axes
# 左连接
pd.concat((df1, df2), axis=1, sort=True, join_axes=[df1.index])  

# 右连接
pd.concat((df1, df2), axis=1, sort=True, join_axes=[df2.index])



'''
3) 使用append()函数添加
有一个函数append专门用于在后面添加
df1.append(other, ignore_index=False, verify_integrity=False, sort=None)
'''
# concat是pd的方法, append是对象的方法
df1.append(df2, sort=True, verify_integrity=False)
8.1.DataFrame的合并
df1 = DataFrame({'name':['张三','李四','Chales'],'id':[1,2,3],'age':[22,21,25]})

df2 = DataFrame({'sex':['男','男','女'],'id':[2,3,4],'group':['sale','search','service']})
display(df1, df2)



pd.merge(left, right, how='inner', 
         on=None, left_on=None, 
         right_on=None, left_index=False, 
         right_index=False, 
         sort=False, suffixes=('_x', '_y'))

# how 默认内连接, 两张表的某列值相等才会筛选出来
# 合并的时候,默认使用内合并

1、第一张表某列索引columns与第二张表的某列索引columns  只有一个列名称相同

    1) 一对一合并   
    pd.merge(df1, df2)

    2) 多对一合并
    pd.merge(df1, df2)

    3) 多对多合并
    pd.merge(df1, df2)

    
2、第一张表某列索引columns与第二张表的某列索引columns 不止一个列名称相同
    使用on=显式指定哪一列为key, 然后再进行合并,当有多个key相同时使用
    其他索引会加上suffixes=('_x', '_y')进行区别
    df1.merge(df2, on='name')
    

3、第一张表某列索引columns与第二张表的某列索引columns列名称不相同,但某列与某列数据的属性一致
   使用left_on和right_on指定左右两边的列作为key,当左右两边的key都不相等时使用
    
    # 没有列名相同,但是有数据相同,也可以合并
    pd.merge(df1, df2, left_on='name', right_on='名字')
        
    # 明确的指定了要合并的列之后,可以left_index来指定要保留的行索引.
    pd.merge(ddd, ddd4, left_on='张三', right_on='张十三', left_index=True)
    
    
    
4、当左边的列和右边的index相同的时候,使用right_index=True    

    # 指定列和索引进行合并
    pd.merge(df1, df2, left_on='age', right_index=True)
    
    

# 合并的时候,默认使用内合并
pd.merge(df1, df2, left_on='name', right_on='名字', how='inner')

# 外合并
pd.merge(ddd, ddd4, left_on='张三', right_on='张十三', how='outer')   # 补NaN


# 左合并
pd.merge(df1, df2, left_on='name', right_on='名字', how='left')  # 左边的表记录全要,左边的记录与右边没有匹配的,右边补NaN

# 右合并
pd.merge(df1, df2, left_on='name', right_on='名字', how='right') # 右边的表记录全要,右边的记录与左边没有匹配的,左边补NaN


当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名
pd.merge(df1, df2, on='name', suffixes=['_df1', '_df2'])
9.数据重复处理、数据替换replace、数据新增map、索引替换
'''
1、检测、删除重复行

使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,
每个元素对应一行,如果该行不是第一次出现,则元素为True
df.duplicated(subset=None, keep='first')
    参数subset: 指定子集中的行是否重复
    参数keep: 从头还是从未开始比较 -- first/last
'''

df = make_df([1,2,3,4],  list('ABCD'))
df.loc[1] = df.loc[2]  # 使之存在重复行
df

display(df.duplicated(keep='last', subset=['A', 'B', 'C']))


'''
使用drop_duplicates()函数删除重复的行
df.drop_duplicates(subset=None, keep='first', inplace=False)
    参数subset: 指定子集中的行是否重复
    参数keep: 从头还是从未开始比较
    参数inplace: 是否改变原DataFrame
    
np.logical_and()   # 与
np.logical_or()    # 或
np.logical_not()   # 非
'''
df.drop_duplicates(subset=['A', 'B', 'C'], keep='last') 

# 第二种方式,传入series,取反,为True才显示
df[~df.duplicated(keep='last', subset=['A', 'B', 'C'])] 

df[np.logical_not(df.duplicated(keep='last', subset=['A', 'B', 'C']))]




'''
2、数据替换
replace()函数:替换元素
'''
mapping = {'原dataframe数据':'要替换的数据'}
mapping = {4: 104, 23: 123, 16: 116, 54: 105, 45: 104, 25: 125}
ddd.replace(mapping)

mapping = {np.nan: 0}  # 替换NaN
ddd.replace(mapping)



'''
3.数据新增/修改
使用map()函数,由已有的列生成一个新列
适合处理某一单独的列
'''
# 使用数学这一列的成绩新建一列computer
mapping = {126: 106, 66: 96, 138: 108,}
ddd['computer'] = ddd['数学'].map(mapping)


# 修改已有列
mapping = {0: 100, 71: 117, 110: 110, 83: 103}
ddd['python'] = ddd['python'].map(mapping)

# map()函数中可以使用lambda函数
ddd['语文'] = ddd['语文'].map(lambda score: score + 20)
ddd

# map()函数中可以使用函数
def convert(score):
    if score >= 120:
        return '优秀'
    elif score >= 90:
        return '及格'
    else: 
        return '不及格'
    
ddd['语文_score'] = ddd['语文'].map(convert)


'''
4.索引替换
rename()
'''
mapping = {'张三': 'Mr Zhang', '李四': 'Mr Lee', '王五': 'Lao Wang', '赵六': 'Mr Six'}
ddd.rename(mapping, axis=0)
10.异常值检测和过滤、抽样、 数据聚合
'''
1.使用describe()函数查看每一列的描述性统计量
含每一列的count、mean、std、min、max等等
'''
ddd.describe()


'''
2.异常值的检测和过滤不是特定的函数, 这是一套方法论.
    1) 定义异常值的标准.
    2) 将这个标准,写成条件.
    3) 根据条件,取反, 把异常值过滤掉.
'''
    例如:新建一个形状为10000*3的标准正态分布的DataFrame(np.random.randn),
    	去除掉所有满足以下情况的行:其中任一元素绝对值大于3倍标准差

    df = DataFrame(data=np.random.randn(10000, 3))
    df.head()

    # 异常值的标准
    df.std()

    # 条件
    cond = (df.abs() > 3* df.std()).any(axis=1)

    # 根据条件,取反, 把异常值过滤掉
    df[~cond]
    
'''
3. 抽样
# 抽样分成两种, 有放回抽样. 无放回抽样.
有放回抽样: 样本可以重复
无放回抽样:样本不可以重复 
''' 
    有放回抽样:
    take和np.random.randint()结合实现有放回抽样.
    df.take(np.random.randint(0, 4, size=4))
    
    无返回抽样:
    take和np.random.permutation([0,1,2,3])结合实现有无返回抽样 --排列组合
    df.take(np.random.permutation([0,1,2,3])) # 1,2,3,4
    
    
    
'''
4.数据聚合
数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。

数据分类处理:

分组:先把数据分为几组
用函数处理:为不同组的数据应用不同的函数以转换数据
合并:把不同组得到的结果合并起来
数据分类处理的核心: groupby()函数
'''   
# 分组
df = DataFrame({'color':['red','white','red','cyan','cyan','green','white','cyan'],
                'price':np.random.randint(0,8,size = 8),
                'weight':np.random.randint(50,55,size = 8)})

df.groupby(by='color')

使用.groups属性查看各行的分组情况:
df.groupby(by='color').groups

# 聚合
df.groupby(by='color').sum() # 会计算所有的列

price_sum = df.groupby(by='color')[['price']].sum() # 推荐写法. 只会计算指定的列.

# 合并
pd.merge(df, price_sum, left_on='color', right_index=True, suffixes=['', '_sum'])

'''
可以使用pd.merge()函数将聚合操作的计算结果添加到df的每一行
使用groupby分组后调用加和等函数进行运算,然后最后可以调用add_prefix(),来修改列名
'''
price_mean.add_prefix('mean_')    # 给列添加前缀
price_mean.add_suffix('_mean')    # 给列添加后缀

11.pandas数据加载
import pandas as pd
from pandas import Series,DataFrame
import numpy as np

'''
1.read_csv()从使用指定分隔符的文件中读取数据形成DataFrame
    常用参数:
    sep:指定文件内容分隔符
    index_col: 指定行索引,如果读取的文件中有
    header: 默认以读取文件的第一行为列索引,指定为None时,以0,1...设置
    
2.read_table()
    默认参数: sep='\t'
'''    
    pd.read_csv('./data/SMSSpamCollection', sep='\t', header=None)  # 指定制表符 => '\t'
    pd.read_csv('./type-.txt', sep='-', header=None)
    pd.read_table('./data/SMSSpamCollection', header=None) # 分隔符是制表符.

'''
3.pd.read_excel()
# 读取excel表格
    sheet_name指定读哪一个sheet页, 
    index_col指定行索引用的列, 
    header指定列索引用哪几行.
'''
pd.read_excel('./123.xlsx', sheet_name=2, index_col=[0,1], header=[0,1])


'''
4.sqlite数据库读取
pd.read_sql()  # 从数据库读取数据形成DataFrame

dataFrame.to_csv()    # 将dataFrame写成csv格式
dataFrame.to_json()   # 将dataFrame写成json格式
dataFrame.to_html()   # 将dataFrame写成html=>table格式
dataFrame.to_sql()    # 将dataFrame写到sqlite数据库中,
'''


# 创建sqlite的连接
import sqlite3
conn = sqlite3.connect('./data.sqlite')
weather_2017 = pd.read_sql('select * from Weather_2017 limit 30', conn, index_col='index')


weather_2017.to_csv('./weather_2017.csv')     # 将dataFrame写成csv格式
weather_2017.to_json('./weather_2017.json')   # 将dataFrame写成json格式
weather_2017.to_html('./weather_2017.html')   # 将dataFrame写成html=>table格式

'''
# 将dataFrame写到sqlite数据库中,
参数:表名,
     conn: 连接对象,
     if_exists: 表存在则追加
'''

weather_2017.to_sql('Weather_2019', conn, if_exists='append')  



'''
5.### 从mysql中读取数据

'''
!pip install pymysql
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='root', database='blog', charset='utf8')
item_dataframe = pd.read_sql('select * from qiushi limit 30', conn)  # 从数据库中读取数据形成DataFrame


# 将DataFrame 写入数据库
!pip install sqlalchemy
from sqlalchemy.engine import create_engine
engine = create_engine('mysql+pymysql://root:root@localhost/qiubai?charset=utf8')
weather_2017.to_sql('Weather_2019', engine)    # 将DataFrame写入到数据库中,=> 一参:表名   二参:数据引擎 -- 对于关系型数据库


# 根据url获取网络上的数据
pd.read_csv('https://raw.githubusercontent.com/datasets/investor-flow-of-funds-us/master/data/weekly.csv')
12.Series与DataFrame简单画图

一、线形图:想看走势就画线形图

    1.Series线形图
    # 以index作为x轴数据,以value作为y轴数据

    s = Series(data=np.random.randint(0, 10, size=10))
    s.plot()



    2.DataFrame线形图
    # 以行索引作为x轴数据,y轴的取值范围取决于data的范围, 每一列就是一条线.

    index = [0, 1 , 2, 3]
    columns = ['语文', '数学', '英语', 'python']
    data = np.random.randint(0, 150, size=(4,4))
    df = DataFrame(index=index, columns=columns, data=data)

    # 改中文字体.
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 修复中文字体下负号不能正常显示的问题.
    plt.rcParams['axes.unicode_minus'] = False

    df.plot()
    
    
二、柱状图:比较大小的时候画柱状图

    1.Series柱状图
    # 以index作为x轴数据,以value作为y轴数据

    s = Series(data=np.random.randint(0, 10, size=10))
    s.plot(kind='bar')     # 垂直柱状图
    s.plot(kind='barh')    # 水平柱状图


    2、DataFrame柱状图
    # 以index索引为X轴, columns每一项都是一个柱形
    index = ['张三', '李四', '王五', '赵六']
    columns = ['语文', '数学', '英语', 'python']
    data = np.random.randint(0, 150, size=(4,4))
    df = DataFrame(index=index, columns=columns, data=data)

    # 改中文字体.
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 修复中文字体下负号不能正常显示的问题.
    plt.rcParams['axes.unicode_minus'] = False

    df.plot(kind='bar')   # 垂直柱状图
    df.plot(kind='barh')  # 水平柱状图  
   


三、直方图: 直方图的Y轴数据是数据出现的次数(频数)
   直方图反映数据的分布情况
    柱高表示数据的频数,柱宽表示各组数据的组距
    参数bins可以设置直方图方柱的个数上限,越大柱宽越小,数据分组越细致
    设置normed参数为True,可以把频数转换为概率
    
    data = np.random.randint(0, 10, size=10)
	s = Series(data)
    s.plot(kind='hist', bins=10)  # y轴是各个数字出现的次数(频数), bins组距
    
    s.plot(kind='hist', bins=10, density=True) # density=True,  y轴的值是概率密度.
    
    
    # 计算直方数据
    # np.histogram(a, bins=10, range=None,)  
    # 参数range 默认取值a的(a.min(), a.max())
    # bins默认为10,会把range区间分为10份来确定每个柱子的x轴区间
    np.histogram(s)   # 2. 到 2.7之间出现1次, 2.7-3.4出现1次
    (array([1, 1, 0, 0, 1, 1, 0, 2, 2, 2], dtype=int64),
 		array([2. , 2.7, 3.4, 4.1, 4.8, 5.5, 6.2, 6.9, 7.6, 8.3, 9. ]))
    
    kde图:核密度估计,用于弥补直方图由于参数bins设置的不合理导致的精度缺失问题
    
    s.plot(kind='hist', bins=10, density=True)
	s.plot(kind='kde')
    
四、散点图:
    散布图是观察两个一维数据数列之间的关系的有效方法,DataFrame对象可用
    df = DataFrame({'A': np.random.randn(1000), 
                    'B':np.random.randn(1000), 
                    'C': np.random.randn(1000), 
                    'D': np.random.randn(1000)})

    df.plot(x='A', y='B', kind='scatter', alpha=0.5) 
    
    
散布图矩阵,当有多个点时,两两点的关系
使用函数:pd.plotting.scatter_matrix(),
参数diagonal:设置对角线的图像类型 
# 散点图矩阵: 可以 用来观察两两之间
_ = pd.plotting.scatter_matrix(df, figsize=(4*4, 4*4), diagonal='kde')
13.常用奇葩方式与函数


# 1.列出目录下的一类文件
	# 方式一
    df = DataFrame()
    for file in os.listdir():
        if file.endswith('csv'):
            temp = pd.read_csv(file)
            df  = df.append(temp)
            
   # 方式二
   [file for file in os.listdir() if re.match('[a-z]+_\d{6}\.csv', file)]
    
   # 方式三
	import glob
	glob.glob('./*.csv')    #相当于 ls *.csv

	# 方式四
    import  os
    for i in os.walk('./'):    #  生成器,当前目录下的所有目录和文件
        print(i)
        print('--------------')


# 2.将ndarray降为一维:
    nd = np.random.randint(0, 100, size=(3, 4, 5))
    nd.ravel()




# 3.  n.reshape(-1, 1)
	n = np.random.randint(0, 10, size=(3, 4))
	n.reshape(-1, 1)
    
    # 首先n.reshape(-1) 是把ndarray变为一维,
    # 然后n.reshape(-1, 1) 是把ndarray变成一列
    也就是说,先前我们不知道z的shape属性是多少,但是想让z变成只有一列,
    行数不知道多少,通过z.reshape(-1,1)



    
# 4. 将相关列转换为索引值

columns = [ 'education', 'marital_status', 
            'occupation', 'race', 'sex',  'native_country']
for col in columns:
    uni = data[col].unique()
    def convert(item):
        index = np.argwhere(uni == item)[0,0]
        return index

    data[col] = data[col].map(convert)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值