一,Series
1,Series的定义
Series类似于一个字典,可以通过index参数定义其“key”值。Series使用pandas.Series来定义。
如下所示:
s = pd.Series([7, "Beijing", 2.17, -12345, "Happy"], index=["A", "B", "C", "D", "E"])
print(s)
结果为:
A 7
B Beijing
C 2.17
D -12345
E Happy
dtype: object
还可以使用字典形式来构造Series,在使用字典构造Series的时候,字典的keys相当于index,values就是values。假定构造一个名为apts的大城市的房价信息的Series,如下所示:
apts = {"Beijing": 55000, "Shanghai": 60000, "Shenzhen": 50000, "Hangzhou": 20000, "Guangzhou": 20000, "Suzhou": None}
apts = pd.Series(apts, name="price")
结果为:
Beijing 55000.0
Guangzhou 20000.0
Hangzhou 20000.0
Shanghai 60000.0
Shenzhen 50000.0
Suzhou NaN
2,Series的数据选择
在选择Series数据的时候可以像对待一个list一样对待Series。对于上面的apts:
apts[3] 结果为:60000.0
apts[[3]] 结果为:Shanghai 60000.0
注意选择数据的时候一定要使用两个[]!
可以通过类似list的切片操作获取数据,若要获取apts中"Guangzhou"到 "shenzhen"的数据,可以有如下五种操作:
apts[[1,2,3,4]]
apts[["Guangzhou","Hangzhou","Shanghai","Shenzhen"]]
apts["Guangzhou":"Shenzhen"]
apts[1:5]
apts[1:-1]
3,boolean indexing
与numpy相同,pandas也有boolean indexing的操作。boolean indexing的比较粗糙的理解就是对于Series名字的操作会对应到Series中每个元素的操作。
以下通过两个小例子来感受一下Boolean indexing的用处:
a,要获取apts中房价一下50000的:
apts[apts < 50000]
输出为:
Guangzhou 20000.0
Hangzhou 20000.0
b,所以城市不是"Beijing"的信息
apts[apts.index != "Beijing"]
3,Series的函数
对于数值型的Series可以使用一些已有的函数来获取Series的平均数,中位数,最大值,最小值等。
apts.median()
apts.mean()
apts.min()
apts.max()
a,获取房价大于平均房价的城市信息:
apts[ apts > apts.mean() ]
b,将房价小于50000的赋值为40000
apts[apts < 50000] = 40000
4,数学运算
类似广播,对数据做了运算之后,就相当于对Series中的每个数据做了运算。
apts / 2
结果为:
Beijing 27500.0
Guangzhou 20000.0
Hangzhou 20000.0
Shanghai 30000.0
Shenzhen 35000.0
Suzhou NaN
Hefei 20000.0
类似的还有平方,取log等运算:
apts ** 2
np.log(apts) #将numpy的运算运用到pandsa上去
5,数据缺失
apts.notnull() #若不为null返回True
apts.isnull() #若为null返回True
将apts中为null的数据赋值为平均数:
apts[apts.isnull()] = apts.mean()
那么会将apts中所以为null的数据赋值为apts的平均值
6,Series的增删
增加:
为apts增加一个城市"Hefei":
tem=pd.Series({"Hefei":20000})
#apts.append会产生一个新的值,不改变原来的值,所以需要赋值符号
apts=apts.append(tem)
删除:
将“Hefei”这一行删除掉:
apts=apts.drop("Hefei")
#apts.drop会产生一个新的值,而不改变原来的值,所以需要赋值符号
二,DataFrame
一个Dataframe就是一张表格,Series表示的是一维数组,Dataframe则是一个二维数组,可以类比成一张excel的spreadsheet。也可以把Dataframe当做一组Series的集合。
1,创建Dataframe
a,可以使用字典的形式来创建一个DataFrame,与创建Series不同的是,用字典创建DataFrame之后,字典的key值为DataFrame的column即列名,字典的value值为DataFrame的数值。
data = {"City": ["Beijing", "Shanghai", "Guangzhou", "Shenzhen", "Hangzhou", "Chongqing"],
"year": [2016, 2017, 2016, 2017, 2016, 2016],
"population": [2100, 2300, 1000, 700, 500, 500]}
temp = pd.DataFrame(data, columns = ["year", "City", "population"],
index=["one", "two", "three", "four", "five", "six"])
得到的DataFrame为:
columns顺序可以指定,但colums中的元素要是已经存在的,否则数据会乱。
也可以使用如下所示的字典格式来定义一个DataFrame:
data = [{"Tom": 999999, "John": 50000, "Lily": 1000}, {"Tom": 99999, "John": 8000, "Lily": 200}]
te=pd.DataFrame(data,columns=["Tom","John","Lily"],index=["one","two"])
结果为:
如上图结果所示,最后的字典的key值会成为DataFrame的列名。
b,使用Series来构造一个DataFrame
定义三个Series然后,将三个Series定义为DataFrame:
prices =pd.Series({'西瓜':2, '铅笔':1, '本子':3})
units =pd.Series({'西瓜':'kg', '铅笔':'zhi', '本子':'ge'})
number =pd.Series({'西瓜':1.6, '铅笔':2, '本子':1})
shopping = pd.DataFrame({'price':prices, 'units':units, 'number':number })
结果为:
使用字典形式定义Series,然后将Series转换为DataFrame,那么字典的key值最后将作为DataFrame的index,字典的Value会作为DataFrame中的值。
使用Series来组成DataFrame的时候,Series的index最后可以作为DataFrame的index。
prices = pd.Series([23,12,16,78],index=["Cup","Cookie","Toothbrush","pants"])
units=pd.Series(["s","bag","ss","strip"],index=["Cup","Cookie","Toothbrush","pants"])
number=pd.Series([1,3,4,2],index=["Cup","Cookie","Toothbrush","pants"])
pd.DataFrame({"Unit_price":prices,"Units":units,"Number":number},columns = ["Number","Units","Unit_price"])
若要三个Series 能够合并的比较好的一个DataFrame那么它们的行index需要是一样的。
2,broadcast
加入一个新的column,默认会broadcast。
先构造一个DataFrame
apts = pd.Series([55000.0,25000.0,20000.0,60000.0,50000.0],index=["Beijing", "Guangzhou", "Hangzhou", "Shanghai", "Shenzhen"])
cars = pd.Series([300000.0,150000.0,200000.0,400000.0,300000.0,200000.0],index=["Beijing", "Chongqing", "Guangzhou", "Shanghai", "Shenzhen", "Tianjin"])
df = pd.DataFrame({'apts':apts,'cars':cars},index=["Beijing", "Chongqing", "Guangzhou", "Hangzhou", "Shanghai", "Shenzhen", "Suzhou", "Tianjin"])
df["income"] = 20000
apts cars income
Beijing 55000.0 300000.0 20000
Chongqing NaN 150000.0 20000
Guangzhou 25000.0 200000.0 20000
Hangzhou 20000.0 NaN 20000
Shanghai 60000.0 400000.0 20000
Shenzhen 50000.0 300000.0 20000
Suzhou NaN NaN 20000
Tianjin NaN 200000.0 20000
如上所示,为df增加了一个income列之后,就会为每一行增加一列。
3,DataFrame的选择
DataFrame的行由index决定:df.index。像数组的下标选择一样,DataFrame选择:
loc方法可以用index选中行
#使用loc方法选择某一行
df.loc["Beijing"]
#使用loc方法选择三行
df.loc[["Shanghai", "Hangzhou", "Suzhou"]]
df.loc["Shanghai":"Suzhou"]
iloc方法可以用数字选中行
df.iloc[0:5]
df.iloc[2,2] #通过在后面加上,2的方式进一步获取下标位2的第3个数据
df.iloc[3]
只选取某几行的某几列
#只选取某几行的某几列
df[["apts", "income"]].loc["Chongqing":"Shanghai"]
df.loc["Chongqing":"Shanghai"][["apts", "income"]]
DataFrame元素赋值
#先获取列然后在loc行信息
df["income"].loc["Beijing"] = 30000
#给一整行赋值
df.loc["Suzhou"] = 0
#给一整列赋值
df["income"] = 15000
还可以用Series来指定需要修改的index以及相对应的value,没有指定的默认用NaN。
a,修改DataFrame中"Chongqing", “Guangzhou”, "Shenzhen"三个城市的价格:
income = pd.Series([10000, 20000, 30000], index=["Chongqing", "Guangzhou", "Shenzhen"])
df.income = income
b,在DataFrame中增加一列"western",来表示是不是"Chongqing"市
df["western"] = df.index == "Chongqing"
4,DataFrame的增删
增加:
为DataFrame的df增加了一行,添加了"shijiazhuang"的信息
columns = df.columns
shijiazhuang=pd.DataFrame([[22300,212300,13000,40900,0]],columns=columns,index=["shijiazhuang"])
df = df.append(shijiazhuang)
如上述代码所示,使用list形式先定义一个DataFrame,然后再将新的DataFrame添加到df上去。
删除:
df = df.drop("shijiazhuang")
使用df.drop来删除"shijiazhuang"的数据。
df = df.drop(["Beijing", "shijiazhuang"])
使用df.drop来删除多行数据。
df.drop(["apts", "income"], axis=1)
df.drop中axis默认为0 删除的行,axis=1则认为删除的是列.
5,我们还可以指定index的名字和列的名字
= "city"
= "info"
6,对缺失数据的处理
df.fillna(value=0)
将df中缺失值赋值为0。
# method="ffill":对于NAN会被上一个记录的值填充上
df.fillna(method="ffill")
# method="bfill":对于NAN会被上一个记录的值填充上
df.fillna(method="bfill")
7,DataFrame中的Index
a,自己建一个index object
index = pd.Index(["Shanghai", "Beijing", "Guangzhou", "Shenzhen"])
index的值是不能被更改的,如下会报错:
index[1] = "Hangzhou"
b,从Series里面拿出一个index object
obj = pd.Series(range(3), index=["a", "b", "c"])
obj_index = obj.index
8,sex_index
#使用set_index来重定义label
df_label = df.set_index("label")
df_label
上述代码是将df中"label"列设置为数据的index列。
#将drop设置成False,列的label就不会消失了
df.set_index("label", drop=False)
还可以将多个列作为index,如下所示:
df.set_index(["city", "year"])
结果如下:
df.reset_index()
reset_index()函数将df的index撤销,回复的最初的状态。
9,DataFrame的condition selection
df数据如下:
x y z
a 0 1 2
b 3 4 5
c 6 7 8
获取df中x小于5的数据:
df[df.x < 5]
还能赋值
df[df<5] = 0
reindex():把一个Series或者DataFrame按照新的index顺序进行重排.
s = pd.Series([4.5, 2.7, 8.9, -0.4], index = ['d', 'b', 'a', 'c'])
s.reindex(['a', 'b', 'c', 'd', 'e'])
10,hierarchical index和unstack,stack:Series
Series中的可以设置双层索引:
data = pd.Series(np.random.randn(10), index = [["a", 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd', 'd'], [1,2,3,1,2,1,2,1,2,3]])
#通过这种方式就可以访问到数据
data['a'][1]
data为:
a 1 1.279207
2 -0.701211
3 0.014934
b 1 -0.405349
2 2.242567
c 1 -1.621013
2 -0.658889
d 1 -1.261036
2 -0.165087
3 0.674639
获取数据"data[“b”: “c”]"为:
b 1 -0.405349
2 2.242567
c 1 -1.621013
2 -0.658889
data[:2]还是按照数据的行排序来选取前两行数据:
a 1 1.279207
2 -0.701211
unstack和stack可以帮助我们在hierarchical indexing和DataFrame之间进行切换。
nstack特定格式的Series转换成DataFrame,stack可以将DF转回到Series
unstacked = data.unstack()
unstacked为:
1 2 3
a 1.279207 -0.701211 0.014934
b -0.405349 2.242567 NaN
c -1.621013 -0.658889 NaN
d -1.261036 -0.165087 0.674639
unstacked.stack()就可以将DataFrame数据转回到Series数据。
11,DataFrame的hierarchical indexing
df = pd.DataFrame(np.arange(12).reshape(4,3),
index = [["a", "a", 'b', 'b'], [1,2,1,2]],
columns = [["x", "y", "y"], [1,1,2]])
结果为:
x y
1 1 2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
获取数据:
df.loc['a':'b'].loc['b']['x'].loc[2][1] #输出为9
df.loc['a'].loc[1]["x"][1] #输出为0
12,csv文件的读取
goog = pd.read_csv("data/GOOG.csv", index_col=0)
读取文件,并将第1列设置为index。
goog = goog.reindex(pd.to_datetime(goog.index))
将goog的index列的类型转变成“datetime”类型。
df.to_csv("data/sample.tsv", sep="\t")
将df存储成以’\t’为分隔符的文件。
三,DataFrame的Group By 以及例子
1,Group By 与 aggravate
以公司的薪水为例:
Salaries = pd.DataFrame({
'Name': ['Tom', 'Lily', 'Lily', 'John', 'Tom', 'Tom', 'Lily', 'Tom'],
'Year': [2016,2016,2016,2016,2017,2017,2017,2017],
'Salary': [10000,2000,4000,5000,18000,25000,3000,4000],
'Bonus': [3000,1000,1000,1200,4000,2300,500,1000]
})
print(Salaries)
结果如下:
a,下面通过分组将名字相同的分成一组:
group_by_name = salaries.groupby('Name')
groupby之后一般要做一些aggregate操作:
将姓名相同的一组,的薪资加在一起,由于year加在一起没有意义,因此不要year这一列:
#可以只取一部分
group_by_name[["Salary", "Bonus"],sort=False].sum()
参数sort=False,让结果不排序。
b,也可以使用agg来对结果做一些aggregate的操作,
group_by_name[["Bonus", "Salary"]].agg([np.sum, np.mean, np.std, np.average])
对分组之后的"Bonus", "Salary"求取和、平均值、方差。
c,还可以自己定义函数,放到agg里面。
现在有一个关于股票的信息:
nvda = pd.read_csv("data/NVDA.csv", index_col=0, parse_dates=["Date"])
key = lambda x: x.year
nv1=nvda.groupby(key)
nv1.sum().head(10)
结果如下所示:
先定义函数key来获取一年中的年份,然后用分组得到一年的数据,最后将一年的数据求和。
d,在agg中定义多个函数
#先groupby,在agg多个函数
nvda.groupby(key).agg([np.mean, np.std]).head()
结果如下所示:
2,transform
假设我们要计算股票在一年中的股票的zscore;
zscore = lambda x: (x-x.mean())/x.std()
transformed = nvda.groupby(key).transform(zscore)
transformed 的结果如下:
这样就得到了每一天股票相对于这一年的股票来说的波动。
不得不说transform是很有用的一个函数。
如下得到一年中股票最高和最低差值(虽然没啥用)
price_range = lambda x: x.max() - x.min()
nvda.groupby(key).transform(price_range).head()
结果如下:
apply、transform、agg的使用
在DataFrame中apply、transform、agg都可以用来处理数据。他们其中也有一些不同。
a)transform方法可以被groupby、resampler、dataframe、series等对象调用。
func与agg中的func的说明完全相同。
其特点是,按元素进行操作,所以输入dataframe与输出dataframe的大小完全相同。
同样支持对不同的轴调用不同的函数,以及通过字符串形式调用内置函数。
它只能对每一列进行计算,所以在groupby()之后,.transform()之前是要指定要操作的列,这点也与apply有很大的不同。
b)transform可以实现的操作,apply都可以,但是反之不成立。agg和apply函数都可以进对一行求和等对处理一行信息的操作,但是transform不可以。同agg一样,与内建函数一起使用时,比apply速度快。
DataFrame聚合之后apply、transform、agg各自使用时的时间消耗,结论:
agg()+python内置方法的计算速度最快,其次是transform()+python内置方法。而 transform() 方法+自定义函数
的组合方法最慢,需要避免使用!