DataFrame 表示一个矩形数据表,包含一个有序的命名列集合,每个列可以是不同的值类型(数字、字符串、布尔值等)。DataFrame 同时具有行索引和列索引;它可以被认为是一个 Series 的字典,所有 Series 都共享同一个索引。
注意:虽然 DataFrame 在物理上是二维的,但我们可以使用分层索引以表格格式表示更高维的数据。
构造 DataFrame 的方法有很多种,最常见的一种是从等长列表或 NumPy 数组的字典中构造。
from pandas import Series, DataFrame
data = {"state": ["Ohio", "Ohio", "Ohio", "Nevada", "Nevada", "Nevada"],
"year": [2000, 2001, 2002, 2001, 2002, 2003],
"pop": [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = DataFrame(data)
print(frame)
输出:
state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
5 Nevada 2003 3.2
与 Series 一样,生成的 DataFrame 将自动分配索引,并且列根据 data 中键的顺序(取决于它们在字典中的插入顺序)放置。
如果我们使用的是 Jupyter 笔记本来运行上面的代码,则 pandas DataFrame 对象将显示为对浏览器更友好的 HTML 表。如下图。
对于大型 DataFrame,head 方法仅选择前五行,tail方法返回最后五行:
frame.head() 输出:
state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
frame.tail() 输出:
state year pop
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
5 Nevada 2003 3.2
在构造DataFrame时,如果需要重新指定列的顺序,可以指定columns参数:
from pandas import Series, DataFrame
data = {"state": ["Ohio", "Ohio", "Ohio", "Nevada", "Nevada", "Nevada"],
"year": [2000, 2001, 2002, 2001, 2002, 2003],
"pop": [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = DataFrame(data, columns=["year", "state", "pop"])
print(frame)
输出:
year state pop
0 2000 Ohio 1.5
1 2001 Ohio 1.7
2 2002 Ohio 3.6
3 2001 Nevada 2.4
4 2002 Nevada 2.9
5 2003 Nevada 3.2
Jupyter notebook输出:
year | state | pop | |
---|---|---|---|
0 | 2000 | Ohio | 1.5 |
1 | 2001 | Ohio | 1.7 |
2 | 2002 | Ohio | 3.6 |
3 | 2001 | Nevada | 2.4 |
4 | 2002 | Nevada | 2.9 |
5 | 2003 | Nevada | 3.2 |
如果传递的columns中包含data不存在的键,则该列数据值为NaN,例如:
from pandas import Series, DataFrame
data = {"state": ["Ohio", "Ohio", "Ohio", "Nevada", "Nevada", "Nevada"],
"year": [2000, 2001, 2002, 2001, 2002, 2003],
"pop": [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame2 = DataFrame(data, columns=["year", "state", "pop", "debt"])
print(frame2)
输出:
year state pop debt
0 2000 Ohio 1.5 NaN
1 2001 Ohio 1.7 NaN
2 2002 Ohio 3.6 NaN
3 2001 Nevada 2.4 NaN
4 2002 Nevada 2.9 NaN
5 2003 Nevada 3.2 NaN
用columns属性查看列信息,frame2.columns 输出:
Index(['year', 'state', 'pop', 'debt'], dtype='object')
可以通过以下方法将DataFrame中的列作为Series检索出来,例如:
frame2['state'] 或者 frame2.state 输出:
0 Ohio
1 Ohio
2 Ohio
3 Nevada
4 Nevada
5 Nevada
Name: state, dtype: object
使用 iloc 和 loc 属性按位置或名称检索行
上面的frame2中,通过frame2.loc[1] 或 frame2.iloc[2] 可以检索出第1行和第2行。
frame2.loc[1]输出:
year 2001
state Ohio
pop 1.7
debt NaN
Name: 1, dtype: object
frame2.iloc[2] 输出:
year 2002
state Ohio
pop 3.6
debt NaN
Name: 2, dtype: object
对于frame2中的“debt”无值列,我们可以这样给它赋值:frame2["debt"] = 16.5 赋值后frame2输出:
year | state | pop | debt | |
---|---|---|---|---|
0 | 2000 | Ohio | 1.5 | 16.5 |
1 | 2001 | Ohio | 1.7 | 16.5 |
2 | 2002 | Ohio | 3.6 | 16.5 |
3 | 2001 | Nevada | 2.4 | 16.5 |
4 | 2002 | Nevada | 2.9 | 16.5 |
5 | 2003 | Nevada | 3.2 | 16.5 |
我们还可以通过将与frame2的列等长的numpy数组赋值给debt列,如下:
frame2["debt"] = np.arange(6.) 赋值后frame2输出:
year | state | pop | debt | |
---|---|---|---|---|
0 | 2000 | Ohio | 1.5 | 0.0 |
1 | 2001 | Ohio | 1.7 | 1.0 |
2 | 2002 | Ohio | 3.6 | 2.0 |
3 | 2001 | Nevada | 2.4 | 3.0 |
4 | 2002 | Nevada | 2.9 | 4.0 |
5 | 2003 | Nevada | 3.2 | 5.0 |
将列表或数组分配给DataFrame的某列时,值的长度必须与 DataFrame 的长度匹配。如果我们分配一个 Series,它的标签将完全重新对齐到 DataFrame 的索引,并在任何不存在的索引值中插入缺失值:
val = pd.Series([-1.2, -1.5, -1.7], index=["two", "four", "five"])
frame2["debt"] = val
frame2输出结果如下:
year | state | pop | debt | |
---|---|---|---|---|
0 | 2000 | Ohio | 1.5 | NaN |
1 | 2001 | Ohio | 1.7 | NaN |
2 | 2002 | Ohio | 3.6 | NaN |
3 | 2001 | Nevada | 2.4 | NaN |
4 | 2002 | Nevada | 2.9 | NaN |
5 | 2003 | Nevada | 3.2 | NaN |
以上将val赋值给debt列,由于val的索引无法跟frame2的索引匹配,所以debt列都赋值成缺失值。
对DataFrame 分配不存在的列将创建新列:frame2["eastern"] = frame2["state"] == "Ohio"
该语句先通过frame2["state"] == "Ohio" 判断state列中的各行的值是否为“Ohio”,如果是输出True,不是输出False,整体输出一个bool型数组,并将该数组赋值给frame2的"eastern"列,又由于在frame2中不存在"eastern"这列,所以会创建该列,执行完这行代码后frame输出如下:
year | state | pop | debt | eastern | |
---|---|---|---|---|---|
0 | 2000 | Ohio | 1.5 | NaN | True |
1 | 2001 | Ohio | 1.7 | NaN | True |
2 | 2002 | Ohio | 3.6 | NaN | True |
3 | 2001 | Nevada | 2.4 | NaN | False |
4 | 2002 | Nevada | 2.9 | NaN | False |
5 | 2003 | Nevada | 3.2 | NaN | False |
注意:不能使用 frame2.eastern属性表示法创建新列。
可以使用del函数删除某列,例如 del frame2["eastern"]
from pandas import Series, DataFrame
data = {"state": ["Ohio", "Ohio", "Ohio", "Nevada", "Nevada", "Nevada"],
"year": [2000, 2001, 2002, 2001, 2002, 2003],
"pop": [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame2 = DataFrame(data, columns=["year", "state", "pop", 'debt'])
frame2["eastern"] = frame2["state"] == "Ohio"
del frame2["eastern"]
print(frame2)
删除eastern列后frame2输出:
year state pop debt
0 2000 Ohio 1.5 NaN
1 2001 Ohio 1.7 NaN
2 2002 Ohio 3.6 NaN
3 2001 Nevada 2.4 NaN
4 2002 Nevada 2.9 NaN
5 2003 Nevada 3.2 NaN
frame2.columns 输出:Index(['year', 'state', 'pop', 'debt'], dtype='object')
通过DataFrame的索引返回的列是基础数据的视图,而不是副本。因此,对 Series 的任何就地修改都将反映在DataFrame 中。可以使用 Series 的 copy 方法显式复制该列。
另一种常见的数据格式是嵌套字典。如果将嵌套字典传递给 DataFrame,pandas 会将外部字典键解释为列,将内部键解释为行索引。例如:
from pandas import Series, DataFrame
populations = {"Ohio": {2000: 1.5, 2001: 1.7, 2002: 3.6},
"Nevada": {2001: 2.4, 2002: 2.9}}
frame3 = DataFrame(populations)
print(frame3)
输出:
Ohio Nevada
2000 1.5 NaN
2001 1.7 2.4
2002 3.6 2.9
可以使用类似于NumPy的符号T,进行行列转换:frame3.T
用Jupyter插件 输出:
2000 | 2001 | 2002 | |
---|---|---|---|
Ohio | 1.5 | 1.7 | 3.6 |
Nevada | NaN | 2.4 | 2.9 |
请注意,如果列并非都具有相同的数据类型,则转置会丢弃列数据类型,因此转置后再转置回来可能会丢失以前的类型信息。在这种情况下,列将变为纯 Python 对象的数组。
用嵌套字典构造DataFrame,内部词典中的键被组合起来,形成结果中的索引。但如果指定了显式索引,则不然,例如:
pd.DataFrame(populations, index=[2001, 2002, 2003]) 输出:
Ohio | Nevada | |
---|---|---|
2001 | 1.7 | 2.4 |
2002 | 3.6 | 2.9 |
2003 | NaN | NaN |
populations中不含2003的键,但我们用index参数指定的索引中包含2003,不包含2000,所以结果中不包含2000所对应的行,包含2003对应的行,但是值为NaN。
可以使用Series类型的字典来构造DataFrame,我们从上面frame3中截取数据形成Series类型,然后构造字典,最后用该字典创建一个DataFrame对象。如下:
from pandas import Series, DataFrame
populations = {"Ohio": {2000: 1.5, 2001: 1.7, 2002: 3.6},
"Nevada": {2001: 2.4, 2002: 2.9}}
frame3 = pd.DataFrame(populations)
print(frame3)
#frame3["Ohio"][:-1]形成Series对象
#2000 1.5
#2001 1.7
#frame3["Nevada"][:2]形成Series对象
#2000 NaN
#2001 2.4
pdata = {"Ohio": frame3["Ohio"][:-1],
"Nevada": frame3["Nevada"][:2]}
tpd = DataFrame(pdata)
print(tpd)
输出结果:
Ohio Nevada
2000 1.5 NaN
2001 1.7 2.4
以下列表是可以传递给DataFrame构造函数的内容:
如果 DataFrame 的索引和列设置了 name 属性,输出DataFrame对象也会显示这些属性:
frame3.index.name = "year" #设置索引名为year
frame3.columns.name = "state" #设置列名为state
frame3输出:
state | Ohio | Nevada |
---|---|---|
year | ||
2000 | 1.5 | NaN |
2001 | 1.7 | 2.4 |
2002 | 3.6 | 2.9 |
与 Series 不同,DataFrame 没有 name 属性。DataFrame 的 to_numpy 方法将 DataFrame 中包含的数据作为二维 ndarray 返回。
frame3.to_numpy()
输出:
[[1.5 nan]
[1.7 2.4]
[3.6 2.9]]
如果 DataFrame 的列是不同的数据类型,则将选择合适的返回数组的数据类型以容纳所有列,例如我们将上面的frame2转换成numpy数组:frame2.to_numpy() 输出
[[2000, 'Ohio', 1.5, nan, True],
[2001, 'Ohio', 1.7, nan, True],
[2002, 'Ohio', 3.6, nan, True],
[2001, 'Nevada', 2.4, nan, False],
[2002, 'Nevada', 2.9, nan, False],
[2003, 'Nevada', 3.2, nan, False]], dtype=object
选择object数据类型,这样所有的列的类型都能包容进去。
先学到这,下次深入学习Series和DataFrame的索引对象