Python For Data Analysis-五章第二节
《Python For Data Analysis》的第五章的第二节主要对pandas模块的一些常用函数进行讲解介绍。
8.1 reindex函数
在上一章最后一节介绍了reindex函数,可以为一个DataFrame指定"新"的index而创建出一个新的dataframe数据,上一章的dataframe基本都是用字典来创建的,用字典的键key作为列索引,本节用NumPy的二维数组来创建一个dataframe再复习一下reindex函数。
import pandas as pd
import numpy as np
v = np.arange(24).reshape([6,4])
print v, "# v"
cols = "aa bb cc dd".split()
rows = "z w p x y t".split()
print cols, "# cols"
print rows, "# rows"
df0 = pd.DataFrame(v, index = rows, columns = cols)
print df0, "# df0"
cols_new = "z w p x y m n".split()
df1 = df0.reindex(cols_new)
print df1, "# df1"
执行结果:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
[20 21 22 23]] # v
['aa', 'bb', 'cc', 'dd'] # cols
['z', 'w', 'p', 'x', 'y', 't'] # rows
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df0
aa bb cc dd
z 0.0 1.0 2.0 3.0
w 4.0 5.0 6.0 7.0
p 8.0 9.0 10.0 11.0
x 12.0 13.0 14.0 15.0
y 16.0 17.0 18.0 19.0
m NaN NaN NaN NaN
n NaN NaN NaN NaN # df1
基于已有的dataframe数据df0调用reindex可以创建新的dataframe数据,对于在已有的dataframe数据df0没有的行索引在新的dataframe数据df1里行填空,当然可以使用reindex的method方法前填充ffill(用前边填充没有数据的行)或后填充bfill数据,但是如果先用method参数要求新的index必须是单调有序的否则会报错且由于pandas版本的问题差异较大,不如reindex后调用datframe的方法函数fflill和bfill还是来实现methond功能。
import pandas as pd
import numpy as np
v = np.arange(24).reshape([6,4])
cols = "aa bb cc dd".split()
rows = "z w p x y t".split()
df0 = pd.DataFrame(v, index = rows, columns = cols)
print df0, "# df0"
cols_new = "z w p n x y m".split()
df1 = df0.reindex(index = cols_new)
print df1, "# df1 reindex"
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df0
aa bb cc dd
z 0.0 1.0 2.0 3.0
w 4.0 5.0 6.0 7.0
p 8.0 9.0 10.0 11.0
n NaN NaN NaN NaN
x 12.0 13.0 14.0 15.0
y 16.0 17.0 18.0 19.0
m NaN NaN NaN NaN # df1 reindex
新的index即cols_new里多了'm'和'n'行,这两行的各列的数据填空NaN,cols_new里少了‘t’行索引所以在新的DataFrame里没有‘t’行。
8.2 ffill方法函数
DataFrame数据的ffill函数可以前向填充空行数据,即用空行的上一行数据填空行,如果空行无前行数据则填空。
import numpy as np
v = np.arange(24).reshape([6,4])
cols = "aa bb cc dd".split()
rows = "z w p x y t".split()
df0 = pd.DataFrame(v, index = rows, columns = cols)
print df0, "# df0"
cols_new = "r z w p n x y m".split()
df1 = df0.reindex(index = cols_new).ffill()
print df1, "# df1 ffill"
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df0
aa bb cc dd
r NaN NaN NaN NaN
z 0.0 1.0 2.0 3.0
w 4.0 5.0 6.0 7.0
p 8.0 9.0 10.0 11.0
n 8.0 9.0 10.0 11.0
x 12.0 13.0 14.0 15.0
y 16.0 17.0 18.0 19.0
m 16.0 17.0 18.0 19.0 # df1 ffill
注意cols_new里新增'r'、'm'、'n'行,‘r’位于第一行没有上一行,所以'r'行填充空NaN,而'n'行用其前行'p'的数据填充,'m'用其前行'y'行的数据来填充,新的行索引里没有't'行,所以新dataframe数据没有't'行数据。
8.3 bfill方法函数
DataFrame数据的ffill函数可以后向填充空行数据,即用空行下一行填,如果空行无下一行填空。
import pandas as pd
import numpy as np
v = np.arange(24).reshape([6,4])
cols = "aa bb cc dd".split()
rows = "z w p x y t".split()
df0 = pd.DataFrame(v, index = rows, columns = cols)
print df0, "# df0"
cols_new = "r z w p n x y m".split()
df1 = df0.reindex(index = cols_new).bfill()
print df1, "# df1 bfill"
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df0
aa bb cc dd
r 0.0 1.0 2.0 3.0
z 0.0 1.0 2.0 3.0
w 4.0 5.0 6.0 7.0
p 8.0 9.0 10.0 11.0
n 12.0 13.0 14.0 15.0
x 12.0 13.0 14.0 15.0
y 16.0 17.0 18.0 19.0
m NaN NaN NaN NaN # df1 bfill
新值的'r'行用其下一行'z'行数据来填充,'n'用'x'行数据填充,而'm'位于最低没有下一行所以填充空NaN。
8.4 用指定数据填充行
DataFrame没有fill_value函数,但reindex可以使用fill_value参数来指定reindex后空行的数据。
import pandas as pd
import numpy as np
v = np.arange(24).reshape([6,4])
cols = "aa bb cc dd".split()
rows = "z w p x y t".split()
df0 = pd.DataFrame(v, index = rows, columns = cols)
print df0, "# df0"
cols_new = "r z w p n x y m".split()
df1 = df0.reindex(index = cols_new,fill_value=100)
print df1, "# df1 fill_value"
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df0
aa bb cc dd
r 100 100 100 100
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
n 100 100 100 100
x 12 13 14 15
y 16 17 18 19
m 100 100 100 100 # df1 fill_value
注意新的DataFrame的'm'、'r'和'n'行都是新的行,各列都填充了100这个值。
8.5 append函数
append的时候,不是对直接对原始dataframe数据进行操作,而是在内存中建立副本,因此需要将副本指针重新赋给原始数据。append函数可以在dataframe尾部添加另外一个Dataframe,问题要考虑的是两个dataframe的列不同时会如何?行名字重复又如何?
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
v2 = np.arange(24, 48).reshape([6,4])
cols1 = "aa bb cc dd".split()
cols2 = "aa bb cc ff".split()
rows1 = "z w p x y t".split()
rows2 = "z w p x y f".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print df1, "# df1"
print "-" * 30
df2 = pd.DataFrame(v2, index = rows2, columns = cols2)
print df2, "# df2"
print "-" * 30
df3 = df1.append(df2,sort=False)
print df3, "# df1 append df2"
print "-" * 30
print df3.loc['z'], "# df3.loc['z']"
print "-" * 30
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
------------------------------
aa bb cc ff
z 24 25 26 27
w 28 29 30 31
p 32 33 34 35
x 36 37 38 39
y 40 41 42 43
f 44 45 46 47 # df2
------------------------------
aa bb cc dd ff
z 0 1 2 3.0 NaN
w 4 5 6 7.0 NaN
p 8 9 10 11.0 NaN
x 12 13 14 15.0 NaN
y 16 17 18 19.0 NaN
t 20 21 22 23.0 NaN
z 24 25 26 NaN 27.0
w 28 29 30 NaN 31.0
p 32 33 34 NaN 35.0
x 36 37 38 NaN 39.0
y 40 41 42 NaN 43.0
f 44 45 46 NaN 47.0 # df1 append df2
------------------------------
aa bb cc dd ff
z 0 1 2 3.0 NaN
z 24 25 26 NaN 27.0 # df3.loc['z']
------------------------------
看来dataframe允许多行具有相同的行名字,例如'z'行在df1和df2里都有,append后df3有两行'z'。对于列如果两个dataframe的列不同,取列的交集,append后的dataframe的列数增加,两个互相没有的列上数据填空。
请注意append后的df3有多个相同的行名,通过loc获取的数据也是多行输出,例如df3.loc['z']
。
8.6 insert在指定位置添加一列
insert函数可以在dataframe指定位置添加一列产生新的dataframe。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print df1, "# df1"
s = pd.Series(np.arange(len(rows1)), index = rows1)
print s, "# s"
df1.insert(df1.columns.get_loc("bb"), "ee", s)
print df1, "# df1 insert"
df1.insert(df1.columns.get_loc("cc"), "ff", [9,9,9,9,9,9])
print df1, "# df1 insert"
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
z 0
w 1
p 2
x 3
y 4
t 5
dtype: int64 # s
aa ee bb cc dd
z 0 0 1 2 3
w 4 1 5 6 7
p 8 2 9 10 11
x 12 3 13 14 15
y 16 4 17 18 19
t 20 5 21 22 23 # df1 insert
aa ee bb ff cc dd
z 0 0 1 9 2 3
w 4 1 5 9 6 7
p 8 2 9 9 10 11
x 12 3 13 9 14 15
y 16 4 17 9 18 19
t 20 5 21 9 22 23 # df1 insert
df1.columns
语句是访问dataframe的列索引,dataframe无论列索引还是行索引均是dataframe的index对象有方法函数get_loc可以返回索引的整形位置信息。而dataframe的insert函数可以在某列(位置)前插入一列数据(可以是series或者列表),影响dataframe本身。
8.7 drop删除数据
dataframe的drop函数可以删除整行或整列的数据。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print df1, "# df1"
print df1.drop("p"), "# df1 drop a row"
print df1.drop(["w", "z"]), "# df1 drop rows"
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1 drop a row
aa bb cc dd
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1 drop rows
drop函数删除指定行后产生新的数据,不影响原来的数据,如果想整列删除需要使用axis=1参数指定1轴。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print df1, "# df1"
print df1.drop("bb", axis = 1), "# df1 drop a col"
print df1.drop(["bb", "cc"], axis = 1), "# df1 drop cols"
执行结果:
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
aa cc dd
z 0 2 3
w 4 6 7
p 8 10 11
x 12 14 15
y 16 18 19
t 20 22 23 # df1 drop a col
aa dd
z 0 3
w 4 7
p 8 11
x 12 15
y 16 19
t 20 23 # df1 drop cols
drop函数如果想印象数据本身,可以使用参数inplace=True
。
8.8 数据的选择
dataframe的数据的选择可以通过索引、切片实现数据的选择,按选择的顺序输出得到一个新的dataframe,也可通过布尔数组来选择数据。 这里简要的总结一下通过位置信息position或行列名字label来选择的规则:
- df[]里放名字或名字集合列表是列选择。放切片是行选择,是数字的切片是行选择不含终点,而名字的切片行选则且含终点。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print "-" * 40
print df1, "# df1"
print "-" * 40
print df1["cc"], '# select a col'
print "-" * 40
print df1[["cc", "dd", "aa"]], '# select cols'
print "-" * 40
print df1[1:2], "# select a row"
print "-" * 40
print df1[:2], "# select rows"
print "-" * 40
print df1[2:5], "# select rows"
print "-" * 40
print df1["w":"y"], "# select rows"
print "-" * 40
执行结果:
----------------------------------------
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
----------------------------------------
z 2
w 6
p 10
x 14
y 18
t 22
Name: cc, dtype: int64 # select a col
----------------------------------------
cc dd aa
z 2 3 0
w 6 7 4
p 10 11 8
x 14 15 12
y 18 19 16
t 22 23 20 # select cols
----------------------------------------
aa bb cc dd
w 4 5 6 7 # select a row
----------------------------------------
aa bb cc dd
z 0 1 2 3
w 4 5 6 7 # select rows
----------------------------------------
aa bb cc dd
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19 # select rows
----------------------------------------
aa bb cc dd
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19 # select rows
----------------------------------------
- df.loc[]只有一个label型参数选择行,第二label参数列选择。一个label选一行,多个label的集合列表选多行,label的切片选多行且含终点数据。这种方式在pandas里叫select by label。
1). 通过loc属性只使用一个label参数选择若干行来组建新数据。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print "-" * 40
print df1, "# df1"
print "-" * 40
print df1.loc["z"], "# select a row"
print "-" * 40
print df1.loc[["p", "w", "t"]], "# select rows"
print "-" * 40
print df1.loc["p":"t"], "# select rows"
print "-" * 40
执行结果:
----------------------------------------
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
----------------------------------------
aa 0
bb 1
cc 2
dd 3
Name: z, dtype: int64 # select a row
----------------------------------------
aa bb cc dd
p 8 9 10 11
w 4 5 6 7
t 20 21 22 23 # select rows
----------------------------------------
aa bb cc dd
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # select rows
----------------------------------------
程序的最后一条语句print df1.loc[["x", "p", "z"]]
选择了df1的"x", "p", "z"三行数据。
2). loc即选择行又选择列。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print "-" * 40
print df1, "# df1"
print "-" * 40
print df1.loc["z", ["cc", "aa"]], "# select a row and cols"
print "-" * 40
print df1.loc[["p", "w", "t"], ["bb", "aa"]], "# select rows and cols"
print "-" * 40
print df1.loc["p":"t", "cc"], "# select rows and a col"
print "-" * 40
print df1.loc["p":"t", "aa":"cc"], "# select rows and a cols"
print "-" * 40
执行结果:
----------------------------------------
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
----------------------------------------
cc 2
aa 0
Name: z, dtype: int64 # select a row and cols
----------------------------------------
bb aa
p 9 8
w 5 4
t 21 20 # select rows and cols
----------------------------------------
p 10
x 14
y 18
t 22
Name: cc, dtype: int64 # select rows and a col
----------------------------------------
aa bb cc
p 8 9 10
x 12 13 14
y 16 17 18
t 20 21 22 # select rows and cols
----------------------------------------
- df.iloc[]的方括号里是行的位置信息position而不是label名字。有单独的一个整数、整数集合列表、整数切片、布尔数组等方式来选择行,这种方式在pandas里称作select by position。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print "-" * 40
print df1, "# df1"
print "-" * 40
print df1.iloc[2], "# select a row"
print "-" * 40
print df1.iloc[2:], "# select rows"
print "-" * 40
print df1.iloc[2:, 2:], "# select rows and cols"
print "-" * 40
执行结果:
----------------------------------------
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
----------------------------------------
aa 8
bb 9
cc 10
dd 11
Name: p, dtype: int64 # select a row
----------------------------------------
aa bb cc dd
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # select rows
----------------------------------------
cc dd
p 10 11
x 14 15
y 18 19
t 22 23 # select rows and cols
----------------------------------------
- 通过bool array来选择若干行数据,不能选择列。布尔数组选择可以用在loc、iloc里。
import pandas as pd
import numpy as np
v1 = np.arange(24).reshape([6,4])
cols1 = "aa bb cc dd".split()
rows1 = "z w p x y t".split()
df1 = pd.DataFrame(v1, index = rows1, columns = cols1)
print df1, "# df1"
print df1["cc"] % 3 == 0, '# df1["cc"] % 3 == 0'
print df1[df1["cc"] % 3 == 0], 'df1[df1["cc"] % 3 == 0]'
执行结果
aa bb cc dd
z 0 1 2 3
w 4 5 6 7
p 8 9 10 11
x 12 13 14 15
y 16 17 18 19
t 20 21 22 23 # df1
z False
w True
p False
x False
y True
t False
Name: cc, dtype: bool # df1["cc"] % 3 == 0
aa bb cc dd
w 4 5 6 7
y 16 17 18 19 df1[df1["cc"] % 3 == 0]
df1[df1["cc"] % 3 == 0]
语句会得到一个bool数组,即结果里的
z False
w True
p False
x False
y True
t False
借助这个布尔数组来选择df1对应为True的行,即'w'和'y'的df1的数据。