# -*- coding:UTF-8 -*- __autor__ = 'zhouli' __date__ = '2019/2/13 21:38' import pandas as pd firsts = pd.DataFrame( { 'val1': 1.0, 'val2': [1, 2, 3, 4], 'val3': ["test", "trains", "tony", "stark"], 'val4': 'iron_man' } ) print(firsts) >>> val1 val2 val3 val4 0 1.0 1 test iron_man 1 1.0 2 trains iron_man 2 1.0 3 tony iron_man 3 1.0 4 stark iron_man
可以看到的是
①pandas会自动帮我们做好了填充,非常方便,但是这也是一个容易出错的点
②默认会生成默认索引
③这种方式是以列的形式赋值
pandas的数据结构:
Pandas的基本数据结构是Series和DataFrame,顾名思义,Series就是序列,类似一维数组
DataFrame则是相当一张二维表格,类似二维数组,他的每一个列都是一个Series。为了定位Series中的元素,pandas提供了index对象,每一个Series都会带一个对应的index,用于标记不同的元素,index的内容不一定是数字,可以是字母,中文等,类似SQL的主键。
类似的DataFrame相当于多个带有同样index的series的组合(本质是series的容器),每个Series都带有唯一的表头,用来标识不同的Series
pd.Series([1,2,3,4]) pd.Series([1,2,3,4], index=['a', 'b', 'c', 'd']) pd.Series({'a':1, 'b':2})
Series是将list和dict结合在一起的新数据类型,
就相当于把array多增加了一个标签索引
st=pd.Series([1,2,3,4], index=['a', 'b', 'c', 'd']) st[['a', 'b']] # 花式索引 st['a'] # 标签索引 st[0] # 下标索引
这样做的好处是什么定位到一个表格中将列名作为标签索引
另外Series默认是标签索引!
举个栗子:
sr = pd.Series(np.arange(20))
sr2 = sr[10:].copy()
sr是什么?
sr2是什么?
那么sr2[10]结果为10
因为[]内默认是按照标签索引来解释,那如果就想用默认的索引怎么办?
sr2.iloc[]代表使用下标(当有冲突的时候)
sr2.loc[]代表使用标签
Series---数据对齐
sr1 = pd.Series([12, 23, 34], index=['c', 'a', 'd']) sr2 = pd.Series([11, 20, 10], index=['d', 'c', 'a']) sr1 + sr2
这种情况的index必须是一致的如果有不相同的部分就会出现NaN
那如果不想变成NaN咋办呢?
sr1 = pd.Series([12, 23, 34], index=['c', 'a', 'd'])
sr2 = pd.Series([11, 20, 10], index=['b', 'c', 'a'])
也就是如何让在索引‘b’处的值为11,在索引‘d’处的值为34呢?
那就是使用pandas提供的算术方法:sub,add,div, mul
比如上面的例子:sr1.add(sr2, fill_value=0)如果不加fill_value还是一样的,fill_value是将不存在的赋值为0
Series---缺失值的处理
可以先通过isnull()方法来判断是不是NaN
与此相反的是还有notnull()方法
sr.notnull()
当然再用花式索引就可以过滤出非缺失值
sr[sr.notnull()]
更加直接的是可以使用sr.dropna()
一样可以过滤掉缺失值
那如果不去掉缺失值sr.fillna(0)
将缺失值赋值为0
但是如果是趋势图,赋值为0就会不连续,因此一般取平均值就可以表达为sr.fillna(sr.mean())
在pandas中sr.mean()默认会跳过NaN取平均值
Series小结:
① 是数组字典的结合体(支持下标和标签索引)
② 整数索引loc和iloc(解释为下标还是标签)
③ 数据对齐(不对齐出现NaN)
④ 确实数据的处理:
1,扔掉dropna(),或者dropna(subset=['列名'])
2,赋值fillna()
DataFrame()
见下方例子:
那么如何按照行的形式来建立数据呢?
pd.DataFrame( data=None, # 数据列表,字典格式时直接同事提供变量名 columns=None # 变量名列表 )
import pandas as pd data = [ [1, "test"], [2, "trains"], [3, "tony"], [4, "stark"], ] colums = ["val1", "val2"] rows = pd.DataFrame( data=data, # 数据列表,字典格式时直接同事提供变量名 columns=colums # 变量名列表 ) print(rows) >>> val1 val2 0 1 test 1 2 trains 2 3 tony 3 4 stark
结合起来Series
pd.DataFrame({"one": pd.Series([1, 2, 3], index=['a', 'b', 'c']), "two": pd.Series([1, 2, 3, 4], index=['b', 'a', 'c', 'd'])})
DataFrame的常用属性
① index 获取行索引
② T 转置(行列交换)
③ colums 获取列索引
④ values 获取值数组
⑤ describe() 获取快速统计
DataFrame的切片和取值
df.loc[‘a, ‘one’] 默认是先是行后是列
不要使用df['one']['a']这种方式
那如果需要切一行那就是df.loc['a',:] ,意思为行是a,列是全部;等同于df.loc['a',]
缺失值的处理:
df.dropna()
①如果仅删除一行全是NaN的数据的时候传递参数df.dropna(how='all')
DataFrame的去重:
在大多数的时间,数据中会存在大量重复的数据,在做分析之前需要进行去重:
data = pd.DataFrame({'k1': ['one']*3+['two']*4, 'k2': [3,2,1,3,3,4,4]})
使用data.drop_duplicates()
可以看到,他在默认的情况下会将完全相同的行进行去重
当加上参数之后,subset代表的是当此值重复,pandas就认为是重复的,keep是决定保留哪一个,一般在使用keep的时候先用sort_values进行排序
如果需要查看重复的行
data[data.duplicated()] # 查看重复的行
删除已有的列:
datas = pd.read_excel(r'C:UserslenovoDesktop高校信息.xlsx', encodinh='gbk') datas.drop(['名次', '类型'], axis=1)
当然后面写的axis=1或者axis='columns'都是指按照列来处理
对列进行重命名:
datas.rename(columns={'学校名称': '大学名称','总分': '大学总分'})
pandas的分组技术:
说不清楚,直接看图吧
datas = pd.read_excel(r'C:UserslenovoDesktop高校信息.xlsx', encodinh='gbk') data = datas[['名次', '类型', '学校名称', '所在城市', '所在省份']] data.head()
比方计算各省的高校数量:
data[['学校名称']].groupby(data['所在省份']).count()
再比如,计算各高校所在城市的数量,并且从高到低排序前十名:
data[['学校名称']].groupby(data['所在城市']).count().sort_values('学校名称', ascending=False).head(10)
那如果想要知道各个省份大学名次之和呢?
data[['名次']].groupby(data['所在省份']).sum().sort_values('名次', ascending=False).tail(10)
当然我们还是可以使用自定义的函数进行聚合,首先需要自定义一个函数
def t_ranges(arr): return arr.max()-arr.min() data[['名次']].groupby(data['所在省份']).agg(t_ranges).sort_values('名次', ascending=False).head(10)
注意,这里使用了agg()函数,agg函数还指出传入多个函数
data[['名次']].groupby(data['所在省份']).agg(['sum', 'mean','max',t_ranges]).tail(10) # 在这里,agg里面传入列表,但是需要传入str字符串
在agg()函数中不仅可以应用同一种函数,还可以通过不同的列应用不同的求解函数,下面需要分别对名次和类型应用不同的统计函数,并输出不同列的数据,
这是可以通过agg自定义函数实现,只需要传入以列名为键值得字典
data[['名次', '类型']].groupby(data['所在省份']).agg({'名次': [t_ranges],'类型':['count']}).head()
agg()函数返回的不是DataFrame格式的,使用apply()函数
data.groupby(data['所在省份']).apply(lambda x: x[:3]).head(9) # 在这里传入一个匿名函数,返回按照省份的前三个高校的信息
pandas的pivot_table(index="XXX", values=["ss", "dd"].aggfunc=np.sum)
index代表统计的数据是以XXX为基础的
values代表统计的数据和XXX之间的关系
aggfunc代表上述两个量之间的关系
pandas的常用函数:
①mean()方法
这个方法是用于求平均值df.mean()会自动忽略NaN
如果是行求平均值的话只需要加上一个参数df.mean(axis=1)即可
②sum()方法(同理上面)
③排序sort_values(by='two') 参数ascending=False倒序排列;如果是多列排序的话by可以传入列表(后面如果加上参数inplace=True,就代表用排好序的数据覆盖原始数据)
④按照索引排列sort_index(axis,……ascending)
Numpy的通用函数同样适合pandas
pandas的时间对象处理
pd.to_datetime(['2001-01-01', '2010/Feb/02']) >>> DatetimeIndex(['2001-01-01', '2010-02-02'],dtype='datetime64[ns]', freq=None)
to_datetime是可以传入数组或者是列表,批量处理时间
pd.date_range()
参数start是开始时间,end为结束时间;如果不指定end,那么periods就是代表长度
freq表示频率,这个就是控制periods,‘H’是小时,‘W’是周,‘W-MON’代表每周一,‘B’代表工作日
就是去除周六周天工作日,‘SM’代表半个月,‘T’是分钟,‘S’是秒,‘A’是年;
更离谱的是freq可以写成1h20min
pd.date_range('2010-01-03', periods=60, freq='1h20min')
时间序列:
我们可以看到date_range产生的是DatetimeIndex,也就是可以说当做series的索引
sr = pd.Series(np.arange(100), index=pd.date_range('2019-01-01',periods=100))
但是可以看到的是索引貌似是字符串,但是我们使用index方法看一下sr.index
他成为一个时间序列了,那有什么好处呢?
①我想查找所有2019年3月的数据
sr['2019-03']
如果仅仅看年就是sr['2019']
sr['2001':'2019-03-08'] 都是可以的
也可以按照周啊,天啊进行重列查看情况
sr.resample('M').sum()
文件的读取:
利用pandas读入文本格式数据文件
import pandas as pd pd.read_csv( filepath_or_buffer='', # 要读入文件的路径 sep=',', # 列分隔符,也可以传递正则表达式 header='infer', # 指定数据中第几行作为变量名,如果是None就是自动生成列名 names=None, # 自定义变量名列表, index_col=None, # 将会被用作索引的列名,多列时只能使用序号列表 usecols=None, # 指定只读入某些列,使用索引列表或名称列表均可 # (0, 1, 3), ["名次", "学校名称", ""] encoding=None, # 读入文件的编码方式 na_values='', # 指定将被读入为缺失值的数值列表,默认下列数据被读入,比如表格中None就读为NaN ''' '','#N/A','#N/A N/A', '#NA', 'NULL'等 '''
parse_dates=True, # 将表中能解释为时间序列的列解释为时间序列,也可以传递列名
) pd.read_table() # 更加通用的文本读取命令
读取CSV格式的文件,也是可以通用于文本文件的读取
那这两个方法有什么读取文本的命令基本上一致,最大的区别的地方在于sep
read_csv是',',而另一个是sep=' ',即tab符号
举个栗子:
这个是中国高校排行榜
high_school = pd.read_csv("high_school.csv", encoding='gbk') print(high_school)
结果如下:
如果不适用read_csv,而是采用read_rable
结果就是这样
但是注意的是,table是按照 来的,所以read_table的读取方式是整行读取,所以没有分割
数据的导入与导出:
1,Excel文件的读入:
high_school = pd.read_excel("high_school1.xlsx", sheet_name="full") print(high_school, high_school.describe() # 查看数据的基本情况)
sheet_name写full或者不写都是一样的,因为默认都是读取第一个sheet
当sheet_name写0的时候也是相当于读取第一个sheet
读入统计软件数据集:
例如读SAS/Stata:
pd.read_sas()
pd.read_stata()
读入数据库的文件:
①读入数据表
pd.read_sql
pd.read_sql( sql='', # 需要执行的sql语句/要读入的表名名称 con='', # SQLAlchemy连接引擎名称 index_col=None, # 将被用作索引的列名称 columns=None, # 将提供表名称时,需要读入的列名称list )
pd.read_sql( sql='basic', # 表名为basic con=eng, # SQLAlchemy连接引擎名称eng )
数据的导出:
to_csv
参数有:
① sep 指定文件分隔符
② na_rep 指定缺失值转换的字符串,默认为‘’
③ header=False 不输出列名一行
④ index=False 不输出行索引一列
⑤ cols 指定输出的列,传入列表
pandas和matplotlib
df.plot()
plt.show()