Pandas之二维数组DataFrame
DataFrame是一个多维数据类型。因为通常使用二维数据,因此,我们可以将DataFrame理解成类似excel的表格型数据,由多列组成,每个列的类型可以不同。Series其实就是一列
因为DataFrame是多维数据类型,因此,DataFrame既有行索引,也有列索引。
DataFrame创建方式
我们可以使用如下的方式创建(初始化)DataFrame类型的对象(常用):
- 二维数组结构(列表,ndarray数组,DataFrame等)类型。
- 字典类型,key为列名,value为一维数组结构(列表,ndarray数组,Series等)。
说明:
- 如果没有显式指定行与列索引,则会自动生成以0开始的整数值索引。我们可以在创建DataFrame对象时,通过index与columns参数指定。
- 可以通过head,tail访问前 / 后N行记录(数据)。
# 使用二维数据结构创建DataFrame。没有指定行列索引,自动生成行列索引。都是从0开始的自然数
array1 = np.random.rand(3, 5)
df = pd.DataFrame(array1)
print(df)
# 错误,超过了2d。
# df_more_than2d = pd.DataFrame(np.random.rand(3, 3, 3))
0 1 2 3 4
0 0.877072 0.941101 0.131574 0.056032 0.141660
1 0.129488 0.211658 0.786556 0.477778 0.912969
2 0.624839 0.336306 0.936274 0.581543 0.541653
# 使用字典来创建DataFrame。一个键值对为一列。key指定列索引,value指定该列的值。
df = pd.DataFrame({"北京":[100, 200, 125, 112], "天津":[109, 203, 123, 112], "上海":[39, 90, 300, 112]})
display(df)
# 显示前N条记录
display(df.head(2))
# 显示后N条记录
display(df.tail(2))
# 随机抽取N条记录
display(df.sample(2))
# 创建DataFrame,指定行,列索引。
df = pd.DataFrame(np.random.rand(3, 5), index=["地区1", "地区2", "地区3"], columns=["北京","天津", "上海","沈阳", "广州"])
display(df)
DataFrame相关属性
- index 索引
- columns 列
- values 值
- shape 形状
- ndim 维度
- dtypes 数据类型
说明:
- 可以通过index访问行索引,columns访问列索引,values访问数据,其中index与columns也可以进行设置(修改)。
- 可以为DataFrame的index与columns属性指定name属性值。
- DataFrame的数据不能超过二维。
df = pd.DataFrame(np.random.rand(3, 5), index=["地区1", "地区2", "地区3"], columns=["北京","天津", "上海","沈阳", "广州"])
# 查看idnex, columns, values等属性
display(df.values, type(df.values)) # 返回DataFrame关联的ndarray数组
display(df.index) # 返回行索引
display(df.columns) # 返回列索引
array([[0.88915553, 0.09234275, 0.41773469, 0.92490647, 0.13286735],
[0.85550017, 0.06293159, 0.75023895, 0.01887861, 0.327761 ],
[0.13309605, 0.98347602, 0.95935583, 0.92139592, 0.48752687]])numpy.ndarrayIndex(['地区1', '地区2', '地区3'], dtype='object')Index(['北京', '天津', '上海', '沈阳', '广州'], dtype='object')
# 返回形状
display(df.shape)
# 返回维度
display(df.ndim)
# 返回各列的类型信息。
display(df.dtypes)
(3, 5)2北京 float64
天津 float64
上海 float64
沈阳 float64
广州 float64
dtype: object
DataFrame相关操作
假设df为DataFrame类型的对象。
列操作
- 获取列【哪个更好些?】
- df[列索引]
- df.列索引
- 增加(修改)列:df[列索引] = 列数据
- 删除列
- del df[列索引]
- df.pop(列索引)
- df.drop(列索引或数组)
行操作
- 获取行
- df.loc 根据标签进行索引。
- df.iloc 根据位置进行索引。
- df.ix 混合索引。先根据标签索引,如果没有找到,则根据位置进行索引(前提是标签不是数值类型)。【已不建议使用, 新版本废弃】
- 增加行:append【多次使用append增加行会比连接计算量更大,可考虑使用pd.concat来代替】
- 删除行
- df.drop(行索引或数组)
行列混合操作:
- 先获取行,再获取列。
- 先获取列,在获取行。
说明:
- drop方法既可以删除行,也可以删除列,通过axis指定轴方向。【可以原地修改,也可以返回修改之后的结果。】
- 通过df[索引]访问是对列进行操作。
- 通过df[切片]访问是对行进行操作。【先按标签,然后按索引访问。如果标签是数值类型,则仅会按标签进行匹配。】
- 通过布尔索引是对行进行操作。
- 通过数组索引是对列进行操作。
这个地方重点区分,极易混淆。换种方式进行总结:
- 行操作:切片 和 布尔数组
- 列操作:索引 和 标签数组/位置数组
df = pd.DataFrame(np.random.rand(5, 5), columns=list("abcde"), index=list("hijkl"))
display(df)
# 获取多个列(返回一个DataFrame,即使只选择一个列)
display(df[["a", "d"]])
# 删除列
df["e"] = [6, 7, 8, 9, 10]
del df["e"]
df["e"] = [6, 7, 8, 9, 10] # 把e列加回去
display(df.pop("e")) # 从df中删除e列,会返回删除的列e
display(df)
h 6
i 7
j 8
k 9
l 10
Name: e, dtype: int64
df2 = df.drop("h", inplace=False, axis=0)
display(df, df2)
# 先构造一个DataFrame
np.random.seed(100)
df = pd.DataFrame(np.random.rand(5, 5), index=list("abcde"), columns=list("yuiop"))
display(df)
# 先获取行,再获取列, 其实loc是从高维到低维逐渐定位的。
display(df.loc["c"]["i"])
display(df.loc["c", "i"])
display(df.loc["c"].loc["i"])
display(df.loc["c"]) # loc函数是从高维到低维依次定位的。不能不指定高维,直接定位到低维
display(df.loc[:, "i"])
0.185328219550075060.185328219550075060.18532821955007506y 0.891322
u 0.209202
i 0.185328
o 0.108377
p 0.219697
Name: c, dtype: float64a 0.424518
b 0.825853
c 0.185328
d 0.171941
e 0.817649
Name: i, dtype: float64
# 先获取列,在获取行。
df["i"].loc["a"] = 3
display(df)
# 标签索引组定位列,然后loc切片行
display(df[["i", "o", "p"]].loc["b":"d"])
# 如果布尔数组是二维结构,则True对应的位置元素原样显示,False对应位置的元素置为空值(NaN)
display(df > 0.5)
display(df[df > 0.5])
display(df["i"] > 0.5)
display(df[df["i"] > 0.5])
df = pd.DataFrame(np.random.rand(5, 5), columns=list("abcde"), index=list("hijkl"))
display(df)
# DataFrame行操作
# 获取行 loc iloc ix
# loc 根据标签获取
# iloc 根据位置获取
# ix 混合索引 先根据标签,然后再根据位置
display(df.loc["i"])
display(df.iloc[1])
# 不建议使用,因为非常容易造成混淆。
display(df.ix["i"])
display(df.ix[1])
a 0.598843
b 0.603805
c 0.105148
d 0.381943
e 0.036476
Name: i, dtype: float64
a 0.598843
b 0.603805
c 0.105148
d 0.381943
e 0.036476
Name: i, dtype: float64
a 0.598843
b 0.603805
c 0.105148
d 0.381943
e 0.036476
Name: i, dtype: float64
a 0.598843
b 0.603805
c 0.105148
d 0.381943
e 0.036476
Name: i, dtype: float64
总结
1)选取某一整行(多个整行)或某一整列(多个整列)数据时,可以用df[]、df.loc[]、df.iloc[],此时df[]的方法书写要简单一些。
2)进行区域选取时,如果只能用标签索引,则使用df.loc[]或df.ix[],如果只能用整数索引,则用df.iloc[]或df.ix[]。不过我看到有资料说,不建议使用df.ix[],因为df.loc[]和df.iloc[]更精确(有吗?我没理解精确在哪,望告知)。
3)如果选取单元格,则df.at[]、df.iat[]、df.loc[]、df.iloc[]都可以,不过要注意参数。
4)选取数据时,返回值存在以下情况:
如果返回值包括单行多列或多行单列时,返回值为Series对象; 如果返回值包括多行多列时,返回值为DataFrame对象; 如果返回值仅为一个单元格(单行单列)时,返回值为基本数据类型,例如str,int等。
5)df[]的方式只能选取行和列数据,不能精确到单元格,所以df[]的返回值一定DataFrame或Series对象。
6)当使用DataFrame的默认索引(整数索引)时,整数索引即为标签索引。
DataFrame 增删改
df = pd.DataFrame(np.random.rand(5, 5), columns=list("abcde"), index=list("hijkl"))
display(df)
# 增加一行
line = pd.Series([23, 33, 12., 334.22, 200], index=list("abcde"), name="p")
df = df.append(line)
display(df)
# 删除一行
df1 = df.drop(["h", "j"])
display(df1)
# 修改一行
df.loc["k"] = pd.Series([1,1,1,1,1], index=list("abcde"))
display(df)
DataFrame结构
DataFrame的一行或一列,都是Series类型的对象。对于行来说,Series对象的name属性值就是行索引名称,其内部元素的值,就是对应的列索引名称。对于列来说,Series对象的name属性值就是列索引名称,其内部元素的值,就是对应的行索引名称。
DataFrame运算
DataFrame的一行或一列都是Series类型的对象。因此,DataFrame可以近似看做是多行或多列Series构成的,Series对象支持的很多操作,对于DataFrame对象也同样适用,我们可以参考之前Series对象的操作。
- 转置
- DataFrame进行运算时,会根据行索引与列索引进行对齐。当索引无法匹配时,产生空值(NaN)。如果不想产生空值,可以使用DataFrame提供的运算函数来代替运算符计算,通过fill_value参数来指定填充值。
- DataFrame与Series混合运算。【默认Series索引匹配DataFrame的列索引,然后进行行广播。可以通过DataFrame对象的运算方法的axis参数,指定匹配方式(匹配行索引还是列索引)。】
df1 = pd.DataFrame(np.arange(9).reshape(3, 3))
df2 = pd.DataFrame(np.arange(9, 18).reshape(3, 3))
display(df1, df2)
display(df1 + df2)
display(df1 * df2)
索引排序
Series与DataFrame对象可以使用sort_index方法对索引进行排序。DataFrame对象在排序时,还可以通过axis参数来指定轴(行索引还是列索引)。也可以通过ascending参数指定升序还是降序。
df = pd.DataFrame(np.random.random((3, 5)), index=[3,1,2], columns=[1,3,5,2,4])
display(df)
# 指定按照行索引排序
display(df.sort_index(axis=0, ascending=False))
# 指定按照列索引排序
display(df.sort_index(axis=1, ascending=True))
df = pd.DataFrame(np.arange(9).reshape(3, 3), index=[3, 1, 2], columns=[6, 4, 5])
display(df)
# 默认根据行索引进行排升序。
df1 = df.sort_index()
display(df1)
# 根据列索引进行排序
df2 = df.sort_index(axis=1)
display(df2)
# 就地修改,不会返回修改后的结果。
df.sort_index(inplace=True)
display(df)
# 默认为升序排序,可以指定为降序排序。
df3 = df.sort_index(ascending=False, axis=1)
display(df3)
值排序
Series与DataFrame对象可以使用sort_values方法对值进行排序。
df = pd.DataFrame([[1,3, 2], [5, 2, 4], [2, 4, 3]], index=[1,3,2], columns=list("cab"))
display(df)
# 按照列排序,指定顺序
df1 = df.sort_values("c", ascending=False)
display(df1)
# 按照行排序,指定顺序
df2 = df.sort_values(1, axis=1, ascending=False)
display(df2)
# 值排序
df = pd.DataFrame([[1, 3, 300], [66, 5, 100], [1, 3, 400]])
display(df)
# 根据第2列排升序
df1 = df.sort_values(2)
display(df1)
# 根据第1行排降序
df2 = df.sort_values(1, axis=1, ascending=False)
display(df2)
DataFrame索引对象Index
Series(DataFrame)的index或者DataFrame的columns就是一个索引对象。
- 索引对象可以向数组那样进行索引访问。
- 索引对象是不可修改的。
DataFrame统计相关方法
- mean / sum / count
- max / min
- cumsum / cumprod
- argmax / argmin
- idxmax / idxmin
- var / std
转载自:https://juejin.cn/post/6844904045694418952