DataFrame数据结构
DataFrame
是一个二维表格的数据结构,类似于数据库中的表格或 Excel 工作表。它由多个 Series
组成,每个 Series
共享相同的索引。DataFrame
可以看作是具有列名和行索引的二维数组。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。
3.2.1 DataFrame的创建
最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。DataFrame会自动加上每一行的索引(和Series一样)。同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。
pd.DataFrame(
data=None,
index: 'Axes | None' = None,
columns: 'Axes | None' = None,
dtype: 'Dtype | None' = None,
copy: 'bool | None' = None,
) -> 'None'
- 通过字典直接创建,行索引默认为0~N-1
aDict = {
"Chinese":[100, 102, 108, 95, 88],
"Math":[120, 118, 102, 98, 114],
"English":[64, 98, 115, 102, 96]
}
d = pd.DataFrame(aDict)
d
>>>
Chinese Math English
0 100 120 64
1 102 118 98
2 108 102 115
3 95 98 102
4 88 114 96
- 指通过numpy二维数组创建
df = pd.DataFrame(np.random.randint(1, 10, (3, 4)), index=['a', 'b', 'c'], columns=['A', 'B', 'C', 'D'])
3.2.2 DataFrame的基本属性与方法
df = pd.DataFrame(np.random.randint(1, 10, (3, 4)), index=['a', 'b', 'c'], columns=['A', 'B', 'C', 'D'])
- values值:二维ndarray数组
df.values
>>> ndarray类型的二维数组
array([[7, 5, 3, 6],
[6, 1, 2, 3],
[5, 6, 6, 1]])
- columns:列索引
df.columns
>>> Index(['A', 'B', 'C', 'D'], dtype='object')
- index:行索引
df.index
>>> Index(['a', 'b', 'c'], dtype='object')
- shape:形状
df.shape
>>> (3, 4)
- head():查看前几条数据,默认5条
df.head(2)
- tail():查看后几条数据,默认5条
df.tail(2)
3.2.3 DataFrame的索引
索引优先对列进行操作,然后对行操作
df = pd.DataFrame(np.random.randint(1, 100, (3, 4)), index=['zs', 'ls', 'ww'], columns=['语文', '数学', '英语', '计算机'])
- 对列进行索引:返回列的Series对象
# 1.通过字典的方式取值
print(df['语文'])
print(df[['数学', '计算机']])
# 2.通过属性的方式取值
print(df.语文)
- 对行进行索引:返回行的Series对象
# 1.使用.loc[行索引名称]进行索引
print(df.loc['zs'])
print(df.loc[['zs', 'ww']])
# 2.使用.iloc[行索引整数]进行索引
print(df.iloc[0])
print(df.iloc[[1, 2]])
- 取DataFrame中的元素:返回元素的值
# 方法,用取列或取行的方式取到Series对象,之后和Series对象的去元素方法一致
# 先去列,再取行
print(df['语文']['zs'])
print(df.语文[0])
print(df.语文.zs)
print(df['语文'].iloc[0])
print(df['语文'].loc['zs'])
# 先取行,再取列
print(df.loc['zs']['语文'])
print(df.loc['zs', '语文'])
print(df.loc['zs'].语文)
print(df.iloc[0][0])
print(df.iloc[0, 0])
3.2.4 DataFrame的切片操作
- 切片:优先对行进行切片
# 1.行切片
print(df[1:3]) #直接切片:左闭右开
print(df.iloc[1:3]) #左闭右开
print(df["zs":"ls"]) #通过索引名切片,左闭右闭
print(df.loc['zs':'ls']) #左闭右闭
# 2.列切片
# 列切片之前必须行切片,且只可以iloc和loc
print(df.iloc[:, 1:4])
print(df.loc[:, '数学':'计算机'])
# 3.同时对行和列切片
print(df.iloc[1:3, 1:4])
# 4.索引和切片一起使用
print(df.iloc[0, 1:3])
3.2.5 DataFrame运算
- 基本代数运算:所有元素均作相关运算
df = pd.DataFrame(np.random.randint(50, 100, (3, 4)), index=['zs', 'ls', 'ww'], columns=['语文', '数学', '英语', '计算机'])
print(df + 100)
print(df - 100)
print(df * 100)
print(df / 100)
print(df // 2)
print(df ** 2)
print(df % 2)
- DataFrame与DataFrame的运算
- 在运算中自动对齐索引
- 如果索引不对应,则补NaN
- DataFrame没有广播机制
df1 = pd.DataFrame(np.random.randint(50, 100, (3, 4)), index=['zs', 'ls', 'ww'], columns=['语文', '数学', '英语', '计算机'])
df2 = pd.DataFrame(np.random.randint(50, 100, (3, 4)), index=['zs', 'ls', 'ww'], columns=['语文', '数学', '英语', '计算机'])
#对应索引相同元素相加
df1 + df2
#索引不相同时,索引不对应处为NaN
df3 = pd.DataFrame(np.random.randint(50, 100, (4, 5)), index=['zs', 'ls', 'ww', 'zl'], columns=['语文', '数学', '英语', '计算机', '软件开发'])
df1 + df3
数学 英语 计算机 语文 软件开发
ls 138.0 141.0 123.0 138.0 NaN
ww 128.0 135.0 161.0 173.0 NaN
zl NaN NaN NaN NaN NaN
zs 132.0 111.0 162.0 146.0 NaN
#如果想要保留索引的值,不想出现NaN则需要调用add()函数
df1.add(df3, fill_value=0)
数学 英语 计算机 语文 软件开发
ls 138.0 141.0 123.0 138.0 79.0
ww 128.0 135.0 161.0 173.0 64.0
zl 60.0 78.0 66.0 98.0 65.0
zs 132.0 111.0 162.0 146.0 65.0
- Series与DataFrame的运算
使用Pandas操作函数:
1.当axis=1:以列为单位操作(参数必须是列),对所有列都有效。(默认)
df1 = pd.DataFrame(np.random.randint(50, 100, (3, 4)), index=['zs', 'ls', 'ww'], columns=['语文', '数学', '英语', '计算机'])
s = pd.Series(np.random.randint(50, 100, (4,)), index=df1.columns)
print(df1 + s)
print(df1.add(s, axis=1))
2.当axis=0:以行为单位操作(参数必须是行),对所有行都有效。
df1 = pd.DataFrame(np.random.randint(50, 100, (3, 4)), index=['zs', 'ls', 'ww'], columns=['语文', '数学', '英语', '计算机'])
s = pd.Series(np.random.randint(50, 100, (3,)), index=df1.index)
print(df1.add(s, axis=0))
3.3 层次化索引
Pandas 的层次化索引(Hierarchical Indexing)允许在一个 DataFrame 或 Series 中使用多个索引级别。这意味着数据可以在多个维度上进行组织和操作。通过层次化索引,可以简化复杂的数据结构,并提高对数据的访问效率。
3.1.1 层次化索引的创建
- 隐式创建:
DataFrame:最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组
data = np.random.randint(0, 100, (4, 4))
#这里“2214班”与“zhangsan”,“lisi”对应,“2215班”与"wangwu","zhaoliu"对应
index = [
["2214班","2214班","2215班","2215班"],
["zhangsan", "lisi", "wangwu", "zhaoliu"]
]
columns = [
["第一学期","第一学期","第二学期","第二学期"],
["加权成绩", "平均成绩","加权成绩", "平均成绩"]
]
df = pd.DataFrame(data, index=index, columns=columns)
df
Series:
data = np.random.randint(0, 100, (4, ))
index = [
["2214班","2214班","2215班","2215班"],
["zhangsan", "lisi", "wangwu", "zhaoliu"]
]
s = pd.Series(data=data, index=index)
s
2214班 zhangsan 85
lisi 98
2215班 wangwu 24
zhaoliu 19
dtype: int32
- 显示创建:
1.使用数组创建:pd.MultiIndex.from_arrays()
# 使用数组创建
data = np.random.randint(0, 100, (4, 4))
index = pd.MultiIndex.from_arrays([
["2214班","2214班","2215班","2215班"],
["zhangsan", "lisi", "wangwu", "zhaoliu"]
])
columns = pd.MultiIndex.from_arrays([
["第一学期","第一学期","第二学期","第二学期"],
["加权成绩", "平均成绩","加权成绩", "平均成绩"]
])
df = pd.DataFrame(data, index=index, columns=columns)
df
2.使用元组创建:pd.MultiIndex.from_tuples()
# 使用元组创建
data = np.random.randint(0, 100, (4, 4))
index = pd.MultiIndex.from_tuples(
(
("2214班","zhangsan"),
("2214班","lisi"),
("2215班","wangwu"),
("2215班","zhaoliu")
)
)
columns = pd.MultiIndex.from_tuples(
(
("第一学期","加权成绩"),
("第一学期","平均成绩"),
("第二学期","加权成绩"),
("第二学期","平均成绩")
)
)
df = pd.DataFrame(data, index=index, columns=columns)
df
3.使用笛卡尔积创建:pd.MultiIndex.from_product()
使用数组创建
data = np.random.randint(0, 100, (4, 4))
index = pd.MultiIndex.from_arrays([
["2214班","2214班","2215班","2215班"],
["zhangsan", "lisi", "wangwu", "zhaoliu"]
])
columns = pd.MultiIndex.from_product([
["第一学期","第二学期"],
["加权成绩", "平均成绩"]
])
df = pd.DataFrame(data, index=index, columns=columns)
df
3.1.2 层次化索引与切片
- Series类型
data = np.random.randint(0, 100, (4, ))
index = [
["A2214班","A2214班","A2215班","A2215班"],
["zhangsan", "lisi", "wangwu", "zhaoliu"]
]
s = pd.Series(data=data, index=index)
s
(1)索引
# 显示索引
#层次化索引需要依次访问每层索引以获取该索引下的Series
print(s['A2214班'])
print(s['A2214班']['zhangsan'])
print(s['A2214班', 'zhangsan'])
print(s['A2214班'][0])
print(s['A2214班'][['zhangsan', 'lisi']])
print(s.loc['A2214班'])
print(s.A2214班)
# 隐式索引:与Series的访问方式一致,无需考虑层次化索引
print(s[0])
print(s.iloc[0])
(2)切片
# 显式切片:需要一层层索引依次切片,不可跨索引切片
s['A2214班':'A2215班']
s['A2214班'][:]
s['zhangsan':'lisi'] #Series([], dtype: int32)
#隐式切片:同Series的切片方式相同
s[0:3]
s.iloc[0:2]
- DataFrame类型
data = np.random.randint(0, 100, (4, 4))
index = pd.MultiIndex.from_arrays([
["A2214班","A2214班","A2215班","A2215班"],
["zhangsan", "lisi", "wangwu", "zhaoliu"]
])
columns = pd.MultiIndex.from_product([
["第一学期","第二学期"],
["加权成绩", "平均成绩"]
])
df = pd.DataFrame(data, index=index, columns=columns)
df
(1)索引:先列后行
# 对列进行索引(默认):若索引包含多行返回DataFrame,若索引只包括单行返回Serires
# 1.显示索引:需要一层层索引访问
df['第一学期']
df['第一学期']['加权成绩']
df.第一学期
df[['第一学期','第二学期']]
# 2.隐式索引: 无需考虑多次索引,但要先访问行
df.iloc[:,0]
# 对行进行索引:若索引包含多行返回DataFrame,若索引只包括单行返回Serires
# 1.显示索引:需要一层层索引访问
df.loc['A2214班']
df.loc['A2214班'].loc['zhangsan']
# 2.隐式索引:无需考虑多次索引
df.iloc[2]
(2)切片:先行后列(建议使用隐式索引)
# 行切片
df.iloc[0:3]
# 列切片
df.iloc[, 0:3]
3.1.3 索引的堆叠
索引堆叠通常指的是对 DataFrame 或 Series 的 层次化索引(MultiIndex) 进行堆叠和展开操作。这种操作可以将数据的索引层级转换,或是将数据的多个层级组合成一个新的层级。
- stack(level: ‘Level’ = -1):将列转为行
# 默认;level=-1是将列的最后一层索引转变为行的最后一层索引
# level=n是将列的最后n层索引转变为行的最后一层索引
# 执行后,返回的 DataFrame 会有一个层次化的索引,原本的DataFrame不改变
data = np.random.randint(0, 100, (4, 4))
index = pd.MultiIndex.from_arrays([
["2214班","2214班","2215班","2215班"],
["zhangsan", "lisi", "wangwu", "zhaoliu"]
])
columns = pd.MultiIndex.from_product([
["第一学期","第二学期"],
["加权成绩", "平均成绩"]
])
df = pd.DataFrame(data, index=index, columns=columns)
display(df, df.stack())
- unstack():将行转为列
df.unstack() #默认将行的最后一个索引转换为列的最后一个索引,由于2214班无wangwu等人所以会NaN填写空缺
3.1.4 索引的聚合
# 每一行相加:axis = 0(默认)
print(df.sum())
print(df.sum(axis=0))
print(df.sum(axis=0, level=0)) #计算行的第0层索引对应的和
print(df.sum(axis=0, level=1)) #计算行的第1层索引对应的和
# 每一列相加:axis = 1
print(df.sum(axis=1, level=0)) #计算列的第0层索引对应的和
print(df.sum(axis=1, level=1)) #计算列的第1层索引对应的和
# # 所有元素之和
df.values.sum()