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