入门Pandas
pandas是Python的一个用于数据分析的库:http://pandas.pydata.org
API速查:http://pandas.pydata.org/pandas-docs/stable/api.html
统计、分组、排序、透视表自由转换,如果你已经很熟悉结构化数据库与Excel的功能,就会知道pandas有过之而无不及。
上手玩Pandas
普通的程序员看到一份数据会怎么做?
- 首先导入库准备处理
import datatime
import json
import codecs
import requests
import scipy as cp
import scipy.stats as spstat
import numpy as np
import pandas as pd
- 使用requests下载iris数据集,进行数据演示。使用open方法将数据集下载到本地。
r = requests.get("http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data")
with codecs.open("SIEP3_Iris.txt","w","utf-8") as f:
f.write(r.text)
使用open方法打开txt后读取前十行
with codecs.open("SIEP3_Iris.txt","r","utf-8") as f:
lines = f.readlines()
for idx,line in enumerate(lines):
print(line)
if idx==10:
break
- 快速识别结构化数据,使用pandas可以快速查看数据集并且得到数据的行数以及列数的信息。
import pandas as pd
irisdata = pd.read_csv("SIEP3_Iris.txt",header = None,encoding = "utf-8")
print(irisdata)
- 快速的操作元数据,将列名赋值到irisdata中
cnames = ["sepal_length","sepal_width","petal_length","petal_width","class"]
irisdata.columns = cnames
print(irisdata)
- 快速过滤,将所有花瓣中达到最大值的取出。
petal_width_max = irisdata[irisdata["petal_width"]==irisdata.petal_width.max()]
print(petal_width_max)
- 快速切片,按照行做抽样,取出三十分之一的数据,取出数据集的前两列。
print(irisdata.iloc[::30,:2])
- 快速统计功能,value_counts()可以进行一个快速统计功能。
print(irisdata["class"].value_counts())
for x in range(4):
g = irisdata.iloc[:x]
print('{0:<12}'.format(g.name.upper()))
print('Statistics: {0:>5} {1:>5} {2:>5} {3:>5}'.format(g.max(),g.min(),round(g.mean(),2),round(g.std(),2)))
- 快速MapReduce功能,结合python的匿名函数,group_by功能,agg功能,可轻松实现MapReduce的逻辑
slogs = lambda x:sp.log(x)*x
entpy = lambda x:sp.exp((slogs(x.sum())-x.map(slogs).sum())/x.sum())
irisdata.groupby("class").agg(entpy)
欢迎来到Pandas的世界
Pandas的重要数据类型:
- DataFrame(二维表)
- Series(一维序列)
- Index(行索引。行级元数据)
Series:pandas的长枪(数据表中的一列或一行,观测向量,一维数组。。。)
数据世界中对于任意一个个体的全面观测,或者对于任意一组个体某一属性的观测,全都可以抽象为Series的概念。
用值构建一个Series:
由默认的index和values组成。
Series = pd.Series(np.random.randn(4))
print(Series,tpye(Series))
print(Series.index)
print(Series.values)
Series支持过滤的原理就如同Numpy。
print(Series>0)
print(Series(Series>0))
当然也支持Broadcasting:
print(Series * 2)
print(Series + 5)
以及Universal Function:
print(np.exp(Series))
f_np = np.frompyfunc(lambda x:np(exp(x * 2 + 5), 1, 1))
print(f_np)
在序列上就使用行标,而不是创建一个二列的数据表,能够轻松辨别哪里是数据,哪里是元数据。
Series = pd.Series(Series.values,index=["norm_"unicode(i) for i in range(4)])
print(Series,type(Series))
print(Series.index,type(Series.index))
print(Series.values)
虽然行是有顺序的,但是仍然能够通过行级的index来访问到数据:
print(Series[["norm_2","norm_3"]])
print("norm_0" in Series)
print("norm_6" in Series)
默认行索引就像行号一样:
print(Series.index)
从Key不重复的Ordered Dict或者Dict来定义Series就不需要担心行索引重复:
Series_Dict = {
"Japan":"Tokto",
"S.Korea":"Seoul",
"China":"Beijing"
}
Series_pdSeries = pd.Series(Series_Dict)
print(Series_pdSeries)
print(Series_pdSeries.value)
print(Series_pdSeries.index)
与Dict区别一: 有序
Series_IndexList = ["Japan","China","Singapore","S.Korea"]
Series_pdSeries = pd.Series(Series_Dict ,index = Series_IndexList)
print(Series_pdSeries)
print(Series_pdSeries.values)
print(Series_pdSeries.index)
print(Series_pdSeries.isnull())
print(Series_pdSeries.notnull())
与Dict区别二: index内值可以重复,尽管不推荐。
Series_IndexList = ["A","B","B","C"]
Series = pd.Series(Series.values,index = Serires_IndexList)
print(Series)
print(Series[["B","A"]])
整个序列级别元素数据信息:name
当数据序列以及index本身有了名字,就可以更方便的进行后续的数据关联啦!
print(Series_pdSeries.name)
print(Series_pdSeries.index.name)
################
Series_pdSeries.name = "Capital Series"
Series_pdSeries.index.name = "Nation"
print(Series_pdSeries.name)
print(Series_pdSeries.index.name)
DataFrame:pandas的战锤(数据表,二维数组)
Series的有序集合,就像R语言的DataFrame一样方便。仔细想想,绝大部分的数据形式都可以表示为DataFrame。
从Numpy二维数组,从文件或者从数据库定义:数据虽好,勿忘列名。
dataNumpy = np.array([
('Japan',"Tokyo",4000),
("S.Korea","Seoul",1300),
("China","Beijing",9100)
])
DF1 = pd.DataFrame(dataNumpy,columns = ["nation","capital","GDP"])
print(DF1)
等长的列数据保存在一个字典(JSON)中,很不幸,字典是无序的。
dataDict = {
"nation":['Tokyo',"Seoul","Beijing"],
"GDP":["4900,1300,9100"],
"capital":["Japan","S.Korea","Beijing"]
}
DF2 = pd.DataFrame(dataDict)
print(DF2)
从另一个DataFrame定义DataFrame:
DF2 = pd.DataFrame(DF2,columns=["nation","capital","GDP"])
print(DF2)
从DataFrame中取出列:两种方法(与JavaScript完全一致)
print(DF2.nation)
print(DF2.capital)
print(DF2["GDP"])
从DataFrame中取出行:两种方法
print(DF2[0:1]) # 给出的实际是DataFrame
print(DF2.ix[0]) # 通过对应的Index给出行
像Numpy切片一样的终极招式:iloc
print(DF2.iloc[0,:])
print(DF2.iloc[:,0])
听说你从Alter Table地狱来?pandas笑了。
然而动态的增加列无法用“.”的方式完成,只能用“[ ]”
DF2["population"] = [1600,130,55]
DF2["region"] = "East_Asian"
print(DF2)
Index:pandas进行数据操作的鬼牌(行级索引)
行级索引是
- 元数据
- 可能由真实数据产生,因此可以视作数据
- 可以由多重索引可就是多个列组合而成
- 可以和列名进行交换,也可以进行堆叠和展开,达到Excel透视表功能。
Index有很多种写法,一些重要的索引类型包括:
- pd.index(普通)
- Int64Index(数值型索引)
- MultiIndex(多重索引,在数据操纵中更详细描述)
- DatatimeIndex(以时间格式作为索引)
- PeriodIndex(含周期的时间格式作为索引)
直接定义普通索引,长得就和普通的Series一样:
index_names = ["a","b","c"]
Series_for_index = pd.Series(index_names)
print(pd.Index(index_names))
print(pd.Index(Series_for_index))
可惜。。。Immutable,牢记!
index_names = ["a","b","c"]
index = pd.Index(index_names)
print(index.get_values())
# index[2] = "d" # 不能这样写
# 扔进去一个含有多元组的List,就有了Immutable
可惜,如果这个List Comperhension改成小括号的话,就不对了。
multi = pd.Index([("Row_"+str(x+1),"Col_"+srt(y+1)) for x in range(4) for y in range(4)])
multi.name = ["index1","index2"]
print(multi)
对于Series来说,如果拥有了多层Index,数据,变形!
下列代码说明
- 二重MultiIndex的Series可以unstack()或者DataFrame。
- DataFrame可以stack成拥有二重MultiIndex的Series。
data_for_multi = pd.Series(range(16),index=multi)
print(data_for_multi)
print(data_for_multi.unstack())
print(data_for_multi.unstack().stack())
我们来看一下非平衡数据的样子:
Row_1,2,3,4和Col_1,2,3,4并不是全组合的。
multi = pd.Index([("Row_"+str(x),"Col_"+str(y)) for x in range(5),for y in range(5)])
print(multi)
data_for_multi = pd.Series(np.arange(10),index = multi)
print(data_for_multi)
print(data_for_multi.unstack())
print(data_for_multi.unstack().stack())
Datetime标准库如此好用,你值得拥有。
dates = [datetime.datetime(2020,1,1),datetime.datetime(2020,3,1),datetime.datetime(2020,3,26)]
pd.DatetimeIndex(dates)
如果你不仅需要时间格式统一,时间频率也想统一的话:
periodindex = pd.period_range("2020-01","2020-03",freq="M")
print(periodindex)
月级精度和日级精度如何转换?asfreq方可办到。
print(periodindex.asfreq("D",how="start"))
print(periodindex.asfreq("D",how="end"))
如何真正的把两种频率的时间精度匹配上?
periodindex_mon = pd.period_range("2020-01","2020-03",freq="M").asfreq("D",how="start")
periodindex_day = pd.period_range("2020-01-01","2020-03-26",freq="D")
print(periodindex_mon)
print(periodindex_day)
粗糙度数据 + reIndex + ffill/bfill
full_ts1 = pd.Series(periodindex_mon,index = periodindex_mon).reindex(periodindex_day)
print(full_ts1)
full_ts2 = pd.Series(periodindex_mon,index = periodindex_mon).reindex(periodindex_day,method="ffill")
print(full_ts2)
full_ts3 = pd.Series(periodindex_mon,index = periodindex_mon).reindex(periodindex_day,method="bfill")
print(full_ts2)
关于索引,方便的操作有哪些?
前面已经描述过了,索引有序、重复,但一定程度上也能通过key来访问,也就是说,某些集合操作都是可以支持的。
index1 = pd.Index(["A","B","B","C","C"])
index2 = pd.Index(["C","D","E","E","F"])
index3 = pd.Index(["B","C","A"])
print(index1.append(index2))
print(index1.difference(index2))
print(index1.intersection(index2))
print(index1.union(index2))
print(index1.isin(index2))
print(index1.delete(2))
print(index1.drop("A"))
print(index1.insert(0,"K"))
print(index1.is_monotonic,index2.is_monotonic,index3.is_monotonic)
print(index1.is_unique,index2.is_unique,index3.is_unique)