二维数据结构DataFrame对象
DataFrame对象是一种二维带标记数据结构,不同列的数据类型可以不同。为了方便理解,可以将DataFrame对象看成一张Excel电子表格,或者是一个由多列Series对象构成的字典。
import numpy as np
import pandas as pd
DataFrame对象的生成
与Series类似,DataFrame对象也可以由多种类型的数据生成:
- 由Series对象为值构成的字典。
- 由一维数组或列表构成的字典。
- 由字典构成的列表或数组。
使用Series对象构成的字典生成
DataFrame对象可以从一组由Series对象为值构成的字典中生成。字典中的值除了Series对象,也可以是另一个字典,因为字典被转换为Series对象。
假设有一个包含两个Series对象的字典d:
s1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
s2 = pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])
d = {"one": s1, "two": s2}
可以用字典d构造一个DataFrame对象:
df = pd.DataFrame(d)
df
one | two | |
---|---|---|
a | 1.0 | 1.0 |
b | 2.0 | 2.0 |
c | 3.0 | 3.0 |
d | NaN | 4.0 |
与Series相比,DataFrame对象要区分不同的行和列,因此有行标记和列标记之分。默认情况下,df的列标记是传入字典的键,可以用属性.columns
查看:
df.columns
Index(['one', 'two'], dtype='object')
行标记是两个Series对象标记的并集,Pandas会自动将两个Series对象的标记进行对齐:
df.index
Index(['a', 'b', 'c', 'd'], dtype='object')
在生成DataFrame时,也可以指定index和columns参数:
pd.DataFrame(d, index=["d", "b", "a"])
one | two | |
---|---|---|
d | NaN | 4.0 |
b | 2.0 | 2.0 |
a | 1.0 | 1.0 |
Pandas会按照给定的顺序从传入的数据中寻找对应的值,如果该值不存在,则使用缺省值np.nan
:
pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
two | three | |
---|---|---|
d | 4.0 | NaN |
b | 2.0 | NaN |
a | 1.0 | NaN |
使用一维数组构成的字典生成
DataFrame对象还可以使用由一维数组或列表构成的字典生成,这些数组和列表必须是等长的:
d = {'one' : [1., 2., 3., 4.],
'two' : [4., 3., 2., 1.]}
pd.DataFrame(d)
one | two | |
---|---|---|
0 | 1.0 | 4.0 |
1 | 2.0 | 3.0 |
2 | 3.0 | 2.0 |
3 | 4.0 | 1.0 |
传入index参数时,该参数的长度也必须与列表长度一致:
pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
one | two | |
---|---|---|
a | 1.0 | 4.0 |
b | 2.0 | 3.0 |
c | 3.0 | 2.0 |
d | 4.0 | 1.0 |
使用字典数组生成
还可以使用字典构成的数组或列表进行构建:
data = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
pd.DataFrame(data)
a | b | c | |
---|---|---|---|
0 | 1 | 2 | NaN |
1 | 5 | 10 | 20.0 |
与Series不同的是,字典的键对应的是列标记,行标记由数组或列表的大小决定。
使用二维数组生成
还可以使用NumPy的二维数组生成:
a = np.array([[1,2,3], [4,5,6]])
pd.DataFrame(a)
0 | 1 | 2 | |
---|---|---|---|
0 | 1 | 2 | 3 |
1 | 4 | 5 | 6 |
DataFrame对象的使用
DataFrame对象不是二维NumPy数组,在使用方法上存在很大差异:
s1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
s2 = pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])
d = {"one": s1, "two": s2}
df = pd.DataFrame(d)
df
one | two | |
---|---|---|
a | 1.0 | 1.0 |
b | 2.0 | 2.0 |
c | 3.0 | 3.0 |
d | NaN | 4.0 |
列相关的操作
DataFrame对象可以看成是一个由Series对象构成的字典,.columns属性对应字典的键,每一列对应字典的值:
df['one']
a 1.0
b 2.0
c 3.0
d NaN
Name: one, dtype: float64
可以像字典一样增加新列:
df["three"] = df["one"] * df["two"]
df["flag"] = df["one"] > 2
df
one | two | three | flag | |
---|---|---|---|---|
a | 1.0 | 1.0 | 1.0 | False |
b | 2.0 | 2.0 | 4.0 | False |
c | 3.0 | 3.0 | 9.0 | True |
d | NaN | 4.0 | NaN | False |
增加新列时,如果新列的值是单一值,Pandas会按照行标记自动进行扩展:
df["four"] = 4
DataFrame对象支持用del关键字或者.pop()方法删除列:
del df["two"]
three = df.pop("three")
three
a 1.0
b 4.0
c 9.0
d NaN
Name: three, dtype: float64
df
one | flag | four | |
---|---|---|---|
a | 1.0 | False | 4 |
b | 2.0 | False | 4 |
c | 3.0 | True | 4 |
d | NaN | False | 4 |
增加一个行标记不完全相同的新列时,Pandas只会保留该列中与原有行标记相同的部分,以保证原DataFrame对象的行标记不变化:
df["foo"] = pd.Series([1,2,3], index=["a", "d", "e"])
df
one | flag | four | foo | |
---|---|---|---|---|
a | 1.0 | False | 4 | 1.0 |
b | 2.0 | False | 4 | NaN |
c | 3.0 | True | 4 | NaN |
d | NaN | False | 4 | 2.0 |
默认情况下,新列的插入位置都在DataFrame对象的最后。可以使用.insert()方法将其插入指定的位置:
df.insert(1, "bar", df["one"])
df
one | bar | flag | four | foo | |
---|---|---|---|---|---|
a | 1.0 | 1.0 | False | 4 | 1.0 |
b | 2.0 | 2.0 | False | 4 | NaN |
c | 3.0 | 3.0 | True | 4 | NaN |
d | NaN | NaN | False | 4 | 2.0 |
行相关的操作
DataFrame对象有两种常用的索引行的方式。可以用.loc
属性索引行标记,返回一个Series对象:
df.loc["b"]
one 2.0
bar 2.0
flag False
four 4
foo NaN
Name: b, dtype: object
也可以用.iloc属性索引位置,得到第二行数据:
df.iloc[1]
one 2.0
bar 2.0
flag False
four 4
foo NaN
Name: b, dtype: object
加法与减法操作
DataFrame对象支持加法和减法的操作,并且按照行列标记对齐的原则进行计算:
df1 = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])
df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])
df1 + df2
A | B | C | D | |
---|---|---|---|---|
0 | -1.906552 | -2.428495 | 1.131278 | NaN |
1 | -0.955872 | -1.476556 | -1.523796 | NaN |
2 | 0.766210 | -0.162112 | 0.190370 | NaN |
3 | -2.866838 | 0.866281 | 1.340097 | NaN |
4 | -2.027247 | 0.972097 | -0.807422 | NaN |
5 | 0.841079 | 0.101313 | -1.701630 | NaN |
6 | 0.318099 | -0.037061 | -1.878293 | NaN |
7 | NaN | NaN | NaN | NaN |
8 | NaN | NaN | NaN | NaN |
9 | NaN | NaN | NaN | NaN |
DataFrame对象还可以与Series对象进行加减操作。与NumPy中的广播机制类似,Pandas会先将Series对象的标记与DataFrame对象的列标记中对应的部分拿出来,然后使用广播机制将Series对象沿着行标记进行扩展:
df1
A | B | C | D | |
---|---|---|---|---|
0 | 0.034677 | -1.447889 | 0.239673 | 0.897156 |
1 | -0.216450 | -0.052522 | 0.237849 | 0.806303 |
2 | 0.260522 | 0.590821 | 0.231546 | -2.164184 |
3 | -1.264539 | 0.947130 | 0.601591 | -0.753204 |
4 | -1.113126 | 0.063686 | -0.379063 | -0.275933 |
5 | 0.596109 | -0.516650 | -1.177866 | 0.075800 |
6 | 1.386725 | -0.328219 | -1.303265 | -0.790358 |
7 | 1.225454 | 0.923503 | 0.715214 | -0.144048 |
8 | -0.982050 | -0.026315 | 1.963732 | 0.638793 |
9 | 0.715773 | -0.767911 | -0.379927 | -1.533615 |
df1 - df1.iloc[0]
A | B | C | D | |
---|---|---|---|---|
0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
1 | -0.251127 | 1.395367 | -0.001824 | -0.090853 |
2 | 0.225845 | 2.038710 | -0.008127 | -3.061340 |
3 | -1.299216 | 2.395019 | 0.361919 | -1.650360 |
4 | -1.147802 | 1.511575 | -0.618736 | -1.173089 |
5 | 0.561432 | 0.931239 | -1.417538 | -0.821356 |
6 | 1.352048 | 1.119670 | -1.542938 | -1.687514 |
7 | 1.190778 | 2.371392 | 0.475542 | -1.041204 |
8 | -1.016727 | 1.421574 | 1.724059 | -0.258363 |
9 | 0.681096 | 0.679978 | -0.619600 | -2.430771 |