Pandas

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
# import matplotlib.pyplot as plt

2、DataFrame

DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(多个series共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。

  • 行索引:index
  • 列索引:columns
  • 值:values(numpy的二维数组)

1)DataFrame的创建

最常用的方法是传递一个字典或二维数组来创建。

# DataFrame([1,2,3,4])
nd = np.random.randint(0,150,size=(5,4))
nd
index=['张三','李四','王老五','zhaoliu','田七']
columns = ['python','java','c','math']
# 成绩表
# 参数 data是数据 index是行索引 columns是列索引
df = DataFrame(data=nd,index=index,columns=columns)
df
DataFrame(data={
    'A':[1,2,3,4],
    'B':[1,2,3,4],
    'C':[1,2,3,4],
})

另外通过导入csv文件得到的也是DataFrame

heights = pd.read_csv('./data/president_heights.csv')
heights

DataFrame属性:values、columns、index、shape

heights.values  # 可以把DataFrame中的数据提取出来 提取出来的是多维数组
heights.columns  # 可以获取列名
heights.index  # 获取行索引
heights.shape

============================================

练习4:

根据以下考试成绩表,创建一个DataFrame,命名为df:

    张三  李四
语文 150  0
数学 150  0
英语 150  0
理综 300  0

============================================

data = [[150,0],[150,0],[150,0],[300,0]]
data
index = ['语文','数学','英语','理综']
columns = ['张三','李四']
DataFrame(data=data,index=index,columns=columns)

2)DataFrame的索引

(1) 对列进行索引

- 通过类似字典的方式
- 通过属性的方式

可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。

df
df['python']  # 获取列 可以通过中括号传入列名
pandas.core.series.Series
type(df['python'])
pandas.core.series.Series
df.python  # 获取到的是 Series
张三         125
李四          67
王老五         14
zhaoliu     24
田七         140
Name: python, dtype: int32

(2) 对行进行索引

- 使用.loc[]加index来进行行索引
- 使用.iloc[]加整数来进行行索引

同样返回一个Series,index为原来的columns。

df
# df['zhaoliu']
# df.zhaoliu
# 行相当于一共一共的样本 列相当于是对象的各种特征
# 列更重要
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-31-b53296e268a4> in <module>()
      1 # df['zhaoliu']
----> 2 df.zhaoliu


~\Anaconda3\lib\site-packages\pandas\core\generic.py in __getattr__(self, name)
   4370             if self._info_axis._can_hold_identifiers_and_holds_name(name):
   4371                 return self[name]
-> 4372             return object.__getattribute__(self, name)
   4373 
   4374     def __setattr__(self, name, value):


AttributeError: 'DataFrame' object has no attribute 'zhaoliu'
df.loc['zhaoliu']  # 获取到的也是Series
df.iloc[3]
python     24
java      147
c          85
math      128
Name: zhaoliu, dtype: int32
# 总结
# 对列进行索引 df['列名'] 或者 df.列名 获取到的是Series
# 对行进行索引 df.loc['行名'] 或者 df.iloc[索引号] 获取到的也是Series

(3) 对元素索引的方法
- 使用列索引
- 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]] 里面的[3,3]看做一个参数)
- 使用values属性(二维numpy数组)

df
df.python
张三         125
李四          67
王老五         14
zhaoliu     24
田七         140
Name: python, dtype: int32
df['python']
df.python.loc['张三']
df.python.iloc[0]
125
df
df.loc['张三'].loc['python']
125
df
# DataFrame的loc和iloc中也可以使用 整数数组索引的形式
df.loc['张三','python']  # loc是 先行后列
125
df.iloc[0,0]
df
df.iloc[0,0]
df.iloc[[0,1]]
df.iloc[[0,0]]
# 总结
# df.loc 里面用字符串索引 df.loc['行名','列名']
# df.iloc 里面用编号 df.iloc[行索引,列索引]
# 韭菜 榴莲 臭豆腐 辣条
# 王总 刘总 班长 学委 也是委员
data = np.random.randint(0,100,size=(5,4))
i = ['王总','刘总','班长','学委','也是委员']
c = ['韭菜','榴莲','臭豆腐','大蒜']
df = DataFrame(data=data,index=i,columns=c)
df

【注意】
直接用中括号时:

  • 索引表示的是列索引
  • 切片表示的是行切片
df['韭菜']  # 索引是列索引
王总      92
刘总      77
班长      96
学委       0
也是委员    46
Name: 韭菜, dtype: int32
df['刘总':'学委']  # 切片是行切片
df[0:3]  # 切片可以用 文字 也可以用数值

如果非要对列进行切片可以使用loc或iloc的整数数组索引的形式

df
df.loc['王总','韭菜']
df.loc['王总':'班长']
df.loc[:,'韭菜':'臭豆腐']
df.iloc[:,0:3]

============================================

练习5:

使用多种方法对df进行索引和切片,并比较其中的区别

获取 王总 刘总 的 所有爱好

获取 所有人的 韭菜 臭豆腐 的喜爱程度

============================================

df
df['王总':'刘总']
df.loc[['王总','刘总']]
df.loc[:,['韭菜','臭豆腐']]
df.values
array([[92,  6, 85,  8],
       [77, 15,  0, 49],
       [96, 63,  1, 37],
       [ 0, 53, 83, 21],
       [46, 91, 54, 10]])
df.values[2,2]

3)DataFrame的运算

(0) df和数值

df
df + 2
df * 2
df.iloc[3] = df.iloc[3] + 200
df.iloc[3] += 200
df
df.iloc[3,0] += 100
df

(1) DataFrame之间的运算

同Series一样:

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

创建DataFrame df1 不同人员的各科目成绩,月考一

df1 = DataFrame(np.random.randint(0,150,size=(5,4)),index=['jack','rose','tom','jerry','bob'],columns=['python','math','english','chinese'])
df1

创建DataFrame df2 不同人员的各科目成绩,月考二
有新学生转入

df2 = DataFrame(np.random.randint(0,150,size=(5,4)),index=['jack','rose','tom','jerry','bob'],columns=['python','math','english','chinese'])
df2
df1+df2

下面是Python 操作符与pandas操作函数的对应表:

Python Operator Pandas Method(s)
+ add()
- sub(), subtract()
* mul(), multiply()
/ truediv(), div(), divide()
// floordiv()
% mod()
** pow()

(2) Series与DataFrame之间的运算

【重要】

  • 使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。(类似于numpy中二维数组与一维数组的运算,但可能出现NaN)

  • 使用pandas操作函数:

      axis=0:以列为单位操作(参数必须是列),对所有列都有效。
      axis=1:以行为单位操作(参数必须是行),对所有行都有效。
    
df1 = DataFrame(data=np.random.randint(0,150,size=(5,5)),index=list('abcde'),columns=list('12345'))
df1
s1 = Series(data=np.random.randint(0,150,size=5),index=list('01234'))
s1
0    138
1    122
2     58
3    111
4     34
dtype: int32
s2 = Series(data=np.random.randint(0,150,size=5),index=list('abcde'))
s2
a     49
b     40
c    128
d     60
e    122
dtype: int32
df1 + s1  # df中的每一行都和Series去相加 是 对应项相加 如果没有对应项 用NaN补
df1 + s2
df1.add(s1)
# df1.add(s2,axis='columns')  # 默认是每一行相加 让列名对应
df1.add(s2,axis='index') 

============================================

练习6:

  1. 假设ddd是期中考试成绩,ddd2是期末考试成绩,请自由创建ddd2,并将其与ddd相加,求期中期末平均值。

  2. 假设张三期中考试数学被发现作弊,要记为0分,如何实现?

  3. 李四因为举报张三作弊立功,期中考试所有科目加100分,如何实现?

  4. 后来老师发现有一道题出错了,为了安抚学生情绪,给每位学生每个科目都加10分,如何实现?

============================================

# 以后就别删这个了
df1 = DataFrame(data=np.random.randint(0,150,size=(3,3)),index=['张三','李四','王五'],columns=['语文','数学','英语'])
df1
# 以后就别删这个了
df2 = DataFrame(data=np.random.randint(0,150,size=(3,3)),index=['张三','李四','王五'],columns=['语文','数学','英语'])
df2
(df1+df2)/2
df1.iloc[0,1] = 0
df1
df1.loc['李四'] += 100
df1
df1+=10
df1
df1>100

处理丢失数据

1.有两种丢失数据:

  • None: Python自带的数据类型 不能参与到任何计算中
  • np.nan(NaN): float类型 能参与计算,但结果总是NaN
np.NaN + 2
nan

2. np.nan(NaN)

数组直接运算会得到nan,但可以使用np.nan*()函数来计算nan,此时视nan为0。

nd = np.array([1,3,5,np.nan])
nd
nd.sum()
# nd.nansum() # ndarray对象是没有nan*()方法的
np.sum(nd)
np.nansum(nd)
Series和DataForm可以直接处理nan

3. pandas中的None与NaN

  1. pandas中None与np.nan都视作np.nan

用randint创建一个5*5的DataFrame作为例子

df = DataFrame(data=np.random.randint(0,10,size=(5,5)),columns=list('abcde'))
df

使用DataFrame行索引与列索引修改一下DataFrame数据(弄出来一些None和NaN)

s1 = Series([1,3,5,np.nan,None])
s1
s1.sum()
df1 = DataFrame([1,3,5,np.nan,None])
df1
df1.sum()

2) pandas中None与np.nan的操作-pandas%E4%B8%ADNone%E4%B8%8Enp.nan%E7%9A%84%E6%93%8D%E4%BD%9C)

  • isnull()
  • notnull()
  • dropna(): 过滤丢失数据
  • fillna(): 填充丢失数据

(1)判断函数

  • isnull()
  • notnull()
df
df.loc[1,'a'] = np.nan
df.loc[3,'b'] = np.nan
df.loc[0,'e'] = np.nan
df
df.isnull()  # 是nan就是True 不是就是False
df.notnull()
# df.any()  # 默认是axis=0 是 每一列
# df.any(axis=1)
df.isnull()  # isnull() 有空值就是true
df.isnull().any()  # any()只要有True就是True
# 所以 通过 any() 发现某一列是True 说明这一列有空值
df.isnull().any(axis=1)  # 可以确定那一行(哪一个样本)里有空值

(2) 过滤函数

dropna()
可以选择过滤的是行还是列(默认为行)

df.dropna()  # 直接干掉有nan的行
# {'any', 'all'}
# df.dropna(how='any')  # 默认是any 就是只要这一行有nan就把这一行干掉
df.dropna(how='all')  # 所有的都是NaN才把这一行干掉
df.iloc[0] = np.nan
df.dropna(how='all')

(3) 填充函数 Series/DataFrame

fillna()

# value=None 可以指定填充的值
df.fillna(value=0)
# method {'backfill', 'bfill', 'pad', 'ffill', None}  从后面找值来填充nan 从前面找值来填充nan
# df.fillna(method='bfill')
# df.fillna(method='ffill')
# axis=None 填充时沿着哪个轴线
df.fillna(method='bfill',axis=1)
df.fillna(method='bfill',limit=1)  # limit 可以限制 连续填充nan的个数
# value=None, method=None, axis=None, inplace=False, limit=None,
# value 设定了 value 表示nan都用这个值来填充
# method 指定从前面填充还是从后面填充
# axis 指定填充内容的轴线 默认竖着的 axis=1就是横着
# inplace 是否替换原df
# limit 最多连续填充几个nan
df.fillna()

pandas的拼接操作

pandas的拼接分为两种:

  • 级联:pd.concat, pd.append (没有重复数据)
  • 合并:pd.merge, pd.join (有重复数据)

1. 使用pd.concat()级联

为方便讲解,我们首先定义两个DataFrame:

# 留着
df1 = DataFrame(nd1)
df1
# 留着
df2 = DataFrame(nd2)
df2
### 1) 简单级联[](http://localhost:8888/notebooks/00/03/c03_pandas_combine.ipynb#1)--%E7%AE%80%E5%8D%95%E7%BA%A7%E8%81%94)
pandas使用pd.concat函数,与np.concatenate函数类似
# objs 就是 要拼接的df
df3 = pd.concat((df1,df2))
df3
df3.loc[0]  # 因为两个df的行名有重复的 所以 按照重复的行名 去检索 获得了两行
# ignore_index=False 忽略原来的索引 重新分配索引 默认是False
df3 = pd.concat((df1,df2),ignore_index=True)
df3
#  axis=0 控制拼接的方向 默认是0 是 纵向拼接
df3 = pd.concat((df1,df2),axis=0)
df3 = pd.concat((df1,df2),axis=1)
df3 = pd.concat((df1,df2),axis=1,ignore_index=True)
df3

2) 不匹配级联-%E4%B8%8D%E5%8C%B9%E9%85%8D%E7%BA%A7%E8%81%94)

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

有3种连接方式:

  • 外连接:补NaN(默认模式)

  • 内连接:只连接匹配的项

  • 指定连接轴 join_axes

# 留着
df3 = DataFrame(data=nd1,columns=list('abc'))
df4 = DataFrame(data=nd2,columns=list('bcd'))
display(df3,df4)
# pd.concat((df3,df4))  # 警告 
pd.concat((df3,df4),sort=False)  # 对不上的列 补NaN
#  join='outer' join用来控制拼接方式 默认outer外联(有的都要) 还 可以 设置 inner (保留相同的列)
pd.concat((df3,df4),sort=False)
pd.concat((df3,df4),join='outer',sort=False)
pd.concat((df3,df4),join='inner',sort=False)
# 另外还可以自己制定拼接那些列
# join_axes=None 可以设定 按照那些列去拼接
pd.concat((df3,df4),join_axes=[df3.columns])
# 还可以自己制定列
index = pd.Index(['b','c'])
pd.concat((df3,df4),join_axes=[index])
# objs, axis=0, join='outer', join_axes=None, ignore_index=False
# objs 传入要拼接的 df
# axis 是 拼接的方向
# join 设定拼接的方式 有inner内联 和 outer外联
# join_axes 用来指定 按照哪些列去拼接
# ignore_index 忽略原来的索引 重新建立索引
pd.concat()

2. 使用pd.merge()合并

merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并

注意每一列元素的顺序不要求一致

1) 一对一合并

2) 多对一合并

3) 多对多合并

t1 = pd.read_excel('./data/demo.xls',sheet_name=0)
t2 = pd.read_excel('./data/demo.xls',sheet_name=1)
t3 = pd.read_excel('./data/demo.xls',sheet_name=2)
t4 = pd.read_excel('./data/demo.xls',sheet_name=3)
t5 = pd.read_excel('./data/demo.xls',sheet_name=4)

案例练习:美国各州人口数据分析

知识补充

series.unique() 可以去重

首先导入文件,并查看数据样本

df_abbr = pd.read_csv('./data/state-abbrevs.csv')
df_abbr
df_areas = pd.read_csv('./data/state-areas.csv')
df_areas
df_popu = pd.read_csv('./data/state-population.csv')
df_popu
df_popu.tail()
df_popu.head()

合并popu与abbrevs两个DataFrame,分别依据state/region列和abbreviation列来合并。

为了保留所有信息,使用外合并。

df1 = pd.merge(df_popu,df_abbr,how='outer',left_on='state/region',right_on='abbreviation')
df1
df1.isnull().any()  # isnull()有空值就是True
# any()这一列有True就是True
# 这一列有空值就是True

去除abbreviation的那一列(axis=1)

# axis默认是0 是干掉指定的行 axis=1是干掉指定的列
df2 = df1.drop(labels='abbreviation',axis=1)  # drop()可以干掉指定的行或者列
df2
df2.isnull().any()

查看存在缺失数据的列。

使用.isnull().any(),只有某一列存在一个缺失数据,就会显示True。

df2.isnull().any(axis=1)  # 获取到一系列的布尔值
# 把布尔值传入中括号 如果布尔值是True就会把对应位置的值取出来
df2[df2.isnull().any(axis=1)]  # 获取有NaN的行
# df2[df2.isnull().any(axis=1)].unique()  # unique是Series的方法 df不能用
df2[df2.isnull().any(axis=1)]['state/region']  # 按照索引把指定列取出 取出来的是Series
df2[df2.isnull().any(axis=1)]['state/region'].unique()
df2[df2.isnull().any(axis=1)]

为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN!

不能直接把值设置给DataFrame 要用DataFrame给DataFrame赋值

# 找state/region中是波多黎各的行 把 state 设置成 Puerto Rico
df2['state/region']=='PR'
# df2[df2['state/region']=='PR']['state'] = 'Puerto Rico'
temp = df2[df2['state/region']=='PR'].copy()
temp
temp['state'] =  'Puerto Rico'
temp
df2[df2['state/region']=='PR']= temp
df2.isnull().any()
# 找state/region中是波多黎各的行 把 state 设置成 Puerto Rico
df2['state/region']=='USA'
# df2[df2['state/region']=='PR']['state'] = 'Puerto Rico'
temp2 = df2[df2['state/region']=='USA'].copy()
temp2
temp2['state'] =  'United States'
temp2
df2[df2['state/region']=='USA'] = temp2
df2.isnull().any()
df3 = df2.dropna()
df3.isnull().any()
合并各州人口数据和面积数据areas,使用外合并。
df4 = pd.merge(df3,df_areas,how='outer')
df4
df4[df4.isnull().any(axis=1)]
df5 = df4.dropna()
df5.isnull().any()

找出2010年的全民人口数据,df.query(查询语句)

df5.query('year==2010&ages=="total"')

对查询结果进行处理,以state列作为新的行索引:set_index

df6 = df5.set_index('state')
df6.head()

计算人口密度。注意是Series/Series,其结果还是一个Series。

density = df6['population']/df6['area (sq. mi)']
density

排序,并找出人口密度最高的五个州sort_values()的密度

# sort_values是对值进行排序
density.sort_values().tail()
density.sort_values().head()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容