pandas中文文档——数据结构介绍2-DataFrame

楼主
我是社区第822297位番薯,欢迎点我头像关注我哦~

DataFrame

DataFrame是一种二维数据结构(我们在基础篇中讲到过),不同的列具有不同的数据类型。你可以想象它是电子表格(比如Excel的表)、数据库表或者是Series组成的字典。DataFrame是pandas中最常用的,跟Series类似,我们也可以从不同数据类型来创建一个DataFrame。

  • 一维ndarray字典,列表字典、字典的字典、Series字典

  • 二维ndarray

  • Series

  • 结构化的ndarray

  • 另外的DataFrame

除了给出数据参数之外,你还可以选择性的给出index(行标签)和colunmns(列标签)参数。

传递的Series字典中的index如果跟指定的DataFrame的index对应不上,那么将会在生成的DataFrame中抛弃对应不上的index部分。

如果没有指定轴标签(index和columns),那么就会根据给出的data来自动生成。

从Series字典或字典生成DataFrame

如果从多个Series来生成DataFrame,得到的结果的index将会是这几个Series的index的并集。

如果要从字典来生成DataFrame,字典是个嵌套字典,那么会首先将嵌套字典转换成Series。

如果没有指定columns,将会由字典的key排序列表生成。

 d = {
    'one':pd.Series([1.0,2.0,3.0],index=list('abc')),
    'two':pd.Series([1.0,2.0,3.0,4.0],index=list('abcd'))
 }
 
 pd.DataFrame(d)
 pd.DataFrame(d,index=list('dba'))
 pd.DataFrame(d,index=list('dba'),columns=['two','three'])

我们可以通过index和columns属性来分别获取DataFrame的行列标签信息。

注意:

如果数据来源是字典,并且指定了columns参数,那么生成的DataFrame将会以columns中指定的值为准,而忽略字典本身的键(key)

df.index
df.columns

从ndarray字典或者是列表字典生成DataFrame

如果要从ndarray字典来创建DataFrame,那么ndarray必须具有相同的长度。如果指定index,那么index的长度也要跟ndarray的长度一致。若未指定index,那么会默认生成一个range(n)(n=len(ndarray))作为index。

d = {
'one':[1.0,2.0,3.0,4.0],
'two':[4.0,3.0,2.0,1.0]
}
pd.DataFrame(d)
pd.DataFrame(d,index=list('abcd'))

从结构化的数组或记录数组生成DataFrame

这种情况跟从字典数组生成DataFrame一样。

data = np.zeros((2,), dtype=[("A", "i4"), ("B", "f4"), ("C", "a10")])
data[:] = [(1, 2.0, "Hello"), (2, 3.0, "World")]
pd.DataFrame(data)
pd.DataFrame(data, index=["first", "second"])
pd.DataFrame(data, columns=["C", "A", "B"])

注意:

DataFrame的功能并不会像numpy的ndarray那样

从字典列表创建DataFrame

data2 = [{"a": 1, "b": 2}, {"a": 5, "b": 10, "c": 20}]
pd.DataFrame(data2)
pd.DataFrame(data2, index=["first", "second"])
pd.DataFrame(data2, columns=["a", "b"])

从元组字典生成DataFrame

我们可以通过传递一个元组字典来生成一个多索引的DataFrame。

pd.DataFrame(
{
('a','b'): {('A','B'):1,('A','C'):2},
("a", "a"): {("A", "C"): 3, ("A", "B"): 4},
("a", "c"): {("A", "B"): 5, ("A", "C"): 6},
("b", "a"): {("A", "C"): 7, ("A", "B"): 8},
("b", "b"): {("A", "D"): 9, ("A", "B"): 10}
}
)

从Series生成DataFrame

从Series生成DataFrame,将会生成一个index和columns跟Series一样的单列DataFrame(如果没有另外指定index和columns)。

命名元组列表生成DataFrame

列表中的命名元组的第一个命名域决定了DataFrame的列名称。余下的命名元组将会作为行数据。如果余下的这些命名元组的某一部分的长度比第一个(作为DataFrame列的元组)要短,那么余下对应不上的列将以缺失值(NaN)补充。如果长度要比作为列的部分长,那么就会报出ValueError异常。

from collections import namedtuple # 导入命名元组包
Point = namedtuple("Point", "x y")
pd.DataFrame([Point(0, 0), Point(0, 3), (2, 3)])
Point3D = namedtuple("Point3D", "x y z")
pd.DataFrame([Point3D(0, 0, 0), Point3D(0, 3, 5), Point(2, 3)])

数据类列表生成DataFrame

数据类在PEP557这里有介绍,它可以传递给DataFrame的数据构造器用以创建一个DataFrame。传递一个dataclasses列表相当于传递了一个字典列表。

请注意,列表中的所有值都应该是dataclasses,如果有其他数据类型,那么将会报TypeError错误。

from dataclasses import make_dataclass
Point = make_dataclass("Point", [("x", int), ("y", int)])
pd.DataFrame([Point(0, 0), Point(0, 3), Point(2, 3)])

缺失值

关于缺失值这部分会有非常多的内容。我们用np.nan来代表缺失值,来处理生成DataFrame时的缺失值。

 

不同的构造函数

DataFrame.from_dict

DataFrame.from_dict可以接受字典组成的字典或者是数组序列组成的字典,由此生成一个DataFrame。它的使用方法跟DataFrame的构造器差不多,区别在于from_dict的orient参数的默认值为'columns'。

pd.DataFrame.from_dict(dict([("A", [1, 2, 3]), ("B", [4, 5, 6])]))

如果传递参数orient='index',那么键值会作为行标签值。这种情况下,你可以传递你需要的列名称。

pd.DataFrame.from_dict(
dict([('A',[1,2,3]),('B',[4,5,6])]),
orient='index',
columns=['one','two','three']
)

DataFrame.from_records

DataFrame.from_records需要提供元组列表或者是具有结构化数据的ndarray。它跟普通的DataFrame构造器使用方法很类似。区别在于,from_records的结果索引可能是结构化数据类型的特定字段。例如:

data
pd.DataFrame.from_records(data, index="C")

选择、添加、删除列

DataFrame进行选择、添加、删除列的操作跟字典的处理方式很接近。

df["one"] # 获取one列
df["three"] = df["one"] * df["two"] # 添加three列,让其为one列和two列的乘积
df["flag"] = df["one"] > 2 # 添加flag列,让其为one列的2倍
df

我们可以像操作字典的删除一样操作DataFrame:

del df["two"] # 删除two列
three = df.pop("three") # 删除three列,并返回删除的three列值赋值给three变量

当我们添加一列等于标量值时,它会自动填充整列都等于这个值:

df["foo"] = "bar"
df

如果我们插入一个Series,它的index与DataFrame不一致,那么Series将会被对齐匹配到DataFrame的对应index上。如果插入的Series的index跟DataFrame没有对应上的,那么会被赋值为NaN:

df["one_trunc"] = df["one"][:2]
df
df['four'] = pd.Series([1,1,13,56],index=list(range(4)))
pd.Series([1,1,13,56],index=list(range(4)))
df

我们可以插入一个长度跟Dataframe的index长度一致的原生ndarrays。

默认地,新插入的列会放在最后一列位置。我们可以使用insert方法来在特定位置插入列:

df.insert(1, "bar", df["one"]) # 我们将one列复制并命名为bar,将其插入第2列的位置

在方法链中添加新列

DataFrame可以使用assign()方法来新增多列,并且可以通过现有列来生成。

df1
df1.assign(G=df1['A']*df1['B'],H=df1['C']+df1['D']) # 添加G列和H列

在上面的例子中,我们插入了一个预先计算的值列。我们还可以使用函数计算来为DataFrame添加新列。

df1.assign(I=lambda x:x['A']**2) # 我们使用lambda函数来生成一个新列

assign方法返回的结果并不会修改原DataFrame数据,而是只返回一个数据副本。

如下图所示,虽然我们使用assign添加了一列,但是原来的df1的值并没有发生变化。

索引和选择

基本的操作如下所示:

操作 语法 结果
选择列 df[标签值] Series
通过标签值选择行 df.loc[标签值] Series
通过行整数索引值选择行 df.iloc[3] Series
对行切片 df[5:10] DataFrame
通过布尔索引选择行 df[布尔表达式] DataFrame

行选择返回的是索引为DataFrame列名的Series。

df.loc["b"]
df.iloc[2]

关于DataFrame的索引和选择数据会单独一章讲解。

数据对齐和计算

两个DataFrame对象进行对齐操作时,它们自动根据列名和行标签值进行对齐。生成的结果会具有这俩DataFrame对象的行和列索引的交集。

df = pd.DataFrame(np.random.randn(10, 4), columns=["A", "B", "C", "D"])
df2 = pd.DataFrame(np.random.randn(7, 3), columns=["A", "B", "C"])
df + df2

当对一个DataFrame和Series进行操作时,默认操作时将Series的index对齐到DataFrame的列上。例如:

df - df.iloc[0]

如果DataFrame要跟标量值进行运算,那么会得到如下结果:

df * 5 + 2 # 得到的结果会是df的每一个值都进行 *5+2 运算

DataFrame间的布尔操作如下所示:

 

转置

我们使用.T属性来获取DataFrame的转置结果,它跟ndarray的操作很类似。

 df[:5].T

(本文转自简道云用户:龙小马)

编辑于 2021-9-16 15:26
分享扩散:

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0回帖数 1关注人数 1875浏览人数
最后回复于:2021-9-16 15:26

返回顶部 返回列表