数据结构简介# 我们将首先对 pandas 的基本数据结构进行快速、非全面的概述,以帮助您入门。有关数据类型、索引、轴标签和对齐的基本行为适用于所有对象。首先,导入 NumPy 并将 pandas 加载到您的命名空间中: In [1]: import numpy as np In [2]: import pandas as pd 从根本上说,数据对齐是固有的。除非您明确这样做,否则标签和数据之间的链接不会被破坏。 我们将简要介绍数据结构,然后在单独的部分中考虑所有广泛的功能和方法类别。 系列# Series是一个一维标记数组,能够保存任何数据类型(整数、字符串、浮点数、Python 对象等)。轴标签统称为索引。创建 a 的基本方法Series是调用: s = pd.Series(data, index=index) 这里,data可以有很多不同的东西: Python 字典 一个ndarray 标量值(如 5) 传递的索引是轴标签的列表。因此,根据数据是什么,这分为几种情况: 来自ndarray 如果data是 ndarray,则索引必须与数据长度相同。如果没有传递索引,则会创建一个具有 value 的索引。[0, ..., len(data) - 1] In [3]: s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"]) In [4]: s Out[4]: a 0.469112 b -0.282863 c -1.509059 d -1.135632 e 1.212112 dtype: float64 In [5]: s.index Out[5]: Index(['a', 'b', 'c', 'd', 'e'], dtype='object') In [6]: pd.Series(np.random.randn(5)) Out[6]: 0 -0.173215 1 0.119209 2 -1.044236 3 -0.861849 4 -2.104569 dtype: float64 笔记 pandas 支持非唯一索引值。如果尝试执行不支持重复索引值的操作,则此时将引发异常。 来自字典 Series可以从字典实例化: In [7]: d = {"b": 1, "a": 0, "c": 2} In [8]: pd.Series(d) Out[8]: b 1 a 0 c 2 dtype: int64 如果传递了索引,则将拉出索引中标签对应的数据中的值。 In [9]: d = {"a": 0.0, "b": 1.0, "c": 2.0} In [10]: pd.Series(d) Out[10]: a 0.0 b 1.0 c 2.0 dtype: float64 In [11]: pd.Series(d, index=["b", "c", "d", "a"]) Out[11]: b 1.0 c 2.0 d NaN a 0.0 dtype: float64 笔记 NaN(不是数字)是 pandas 中使用的标准缺失数据标记。 从标量值 如果data是标量值,则必须提供索引。该值将重复以匹配索引的长度。 In [12]: pd.Series(5.0, index=["a", "b", "c", "d", "e"]) Out[12]: a 5.0 b 5.0 c 5.0 d 5.0 e 5.0 dtype: float64 系列类似于 ndarray # Series其行为与 a 非常相似,ndarray并且是大多数 NumPy 函数的有效参数。然而,切片等操作也会对索引进行切片。 In [13]: s.iloc[0] Out[13]: 0.4691122999071863 In [14]: s.iloc[:3] Out[14]: a 0.469112 b -0.282863 c -1.509059 dtype: float64 In [15]: s[s > s.median()] Out[15]: a 0.469112 e 1.212112 dtype: float64 In [16]: s.iloc[[4, 3, 1]] Out[16]: e 1.212112 d -1.135632 b -0.282863 dtype: float64 In [17]: np.exp(s) Out[17]: a 1.598575 b 0.753623 c 0.221118 d 0.321219 e 3.360575 dtype: float64 笔记 我们将像索引部分 一样讨论基于数组的索引。s.iloc[[4, 3, 1]] 与 NumPy 数组一样,pandas 也Series有一个dtype. In [18]: s.dtype Out[18]: dtype('float64') 这通常是 NumPy dtype。然而,pandas 和第 3 方库在几个地方扩展了 NumPy 的类型系统,在这种情况下,dtype 将是ExtensionDtype. pandas 中的一些示例是分类数据和可为空整数数据类型。有关更多信息,请参阅dtypes 。 如果您需要支持 a 的实际数组Series,请使用Series.array. In [19]: s.array Out[19]: <NumpyExtensionArray> [ 0.4691122999071863, -0.2828633443286633, -1.5090585031735124, -1.1356323710171934, 1.2121120250208506] Length: 5, dtype: float64 当您需要在没有索引的情况下执行某些操作(例如禁用自动对齐)时,访问数组会很有用。 Series.array永远是一个ExtensionArray.简而言之,ExtensionArray 是一个或多个具体数组(如 numpy.ndarray. pandas 知道如何获取 aExtensionArray并将其存储在 aSeries或 a 的列中DataFrame。有关更多信息,请参阅dtypes。 虽然Series与 ndarray 类似,但如果您需要实际的ndarray,请使用 Series.to_numpy(). In [20]: s.to_numpy() Out[20]: array([ 0.4691, -0.2829, -1.5091, -1.1356, 1.2121]) 即使Series由 a 支持ExtensionArray, Series.to_numpy()也会返回 NumPy ndarray。 系列类似于字典# ASeries也类似于固定大小的字典,您可以通过索引标签获取和设置值: In [21]: s["a"] Out[21]: 0.4691122999071863 In [22]: s["e"] = 12.0 In [23]: s Out[23]: a 0.469112 b -0.282863 c -1.509059 d -1.135632 e 12.000000 dtype: float64 In [24]: "e" in s Out[24]: True In [25]: "f" in s Out[25]: False 如果索引中不包含标签,则会引发异常: In [26]: s["f"] --------------------------------------------------------------------------- KeyError Traceback (most recent call last) File ~/work/pandas/pandas/pandas/core/indexes/base.py:3805, in Index.get_loc(self, key) 3804 try: -> 3805 return self._engine.get_loc(casted_key) 3806 except KeyError as err: File index.pyx:167, in pandas._libs.index.IndexEngine.get_loc() File index.pyx:196, in pandas._libs.index.IndexEngine.get_loc() File pandas/_libs/hashtable_class_helper.pxi:7081, in pandas._libs.hashtable.PyObjectHashTable.get_item() File pandas/_libs/hashtable_class_helper.pxi:7089, in pandas._libs.hashtable.PyObjectHashTable.get_item() KeyError: 'f' The above exception was the direct cause of the following exception: KeyError Traceback (most recent call last) Cell In[26], line 1 ----> 1 s["f"] File ~/work/pandas/pandas/pandas/core/series.py:1121, in Series.__getitem__(self, key) 1118 return self._values[key] 1120 elif key_is_scalar: -> 1121 return self._get_value(key) 1123 # Convert generator to list before going through hashable part 1124 # (We will iterate through the generator there to check for slices) 1125 if is_iterator(key): File ~/work/pandas/pandas/pandas/core/series.py:1237, in Series._get_value(self, label, takeable) 1234 return self._values[label] 1236 # Similar to Index.get_value, but we do not fall back to positional -> 1237 loc = self.index.get_loc(label) 1239 if is_integer(loc): 1240 return self._values[loc] File ~/work/pandas/pandas/pandas/core/indexes/base.py:3812, in Index.get_loc(self, key) 3807 if isinstance(casted_key, slice) or ( 3808 isinstance(casted_key, abc.Iterable) 3809 and any(isinstance(x, slice) for x in casted_key) 3810 ): 3811 raise InvalidIndexError(key) -> 3812 raise KeyError(key) from err 3813 except TypeError: 3814 # If we have a listlike key, _check_indexing_error will raise 3815 # InvalidIndexError. Otherwise we fall through and re-raise 3816 # the TypeError. 3817 self._check_indexing_error(key) KeyError: 'f' 使用该Series.get()方法,丢失的标签将返回 None 或指定的默认值: In [27]: s.get("f") In [28]: s.get("f", np.nan) Out[28]: nan 这些标签也可以通过attribute来访问。 矢量化操作和标签对齐系列# 使用原始 NumPy 数组时,通常不需要逐值循环。Series在 pandas 中 使用时也是如此。Series也可以传递到大多数需要 ndarray 的 NumPy 方法中。 In [29]: s + s Out[29]: a 0.938225 b -0.565727 c -3.018117 d -2.271265 e 24.000000 dtype: float64 In [30]: s * 2 Out[30]: a 0.938225 b -0.565727 c -3.018117 d -2.271265 e 24.000000 dtype: float64 In [31]: np.exp(s) Out[31]: a 1.598575 b 0.753623 c 0.221118 d 0.321219 e 162754.791419 dtype: float64 Series和 ndarray之间的一个关键区别是,它们之间的操作Series 会根据标签自动对齐数据。因此,您可以在编写计算时无需考虑所Series涉及的标签是否相同。 In [32]: s.iloc[1:] + s.iloc[:-1] Out[32]: a NaN b -0.565727 c -3.018117 d -2.271265 e NaN dtype: float64 未对齐之间的运算结果Series将包含所涉及索引的并集。如果在其中一个或另一个中找不到标签Series,结果将被标记为丢失NaN。能够在不进行任何显式数据对齐的情况下编写代码,为交互式数据分析和研究提供了巨大的自由度和灵活性。 pandas 数据结构的集成数据对齐功能使 pandas 与大多数处理标记数据的相关工具区分开来。 笔记 一般来说,我们选择使不同索引对象之间的操作的默认结果产生索引的并集,以避免信息丢失。尽管缺少数据,但拥有索引标签通常是计算过程中的重要信息。您当然可以选择通过 dropna函数删除丢失数据的标签。 名称属性# Series还有一个name属性: In [33]: s = pd.Series(np.random.randn(5), name="something") In [34]: s Out[34]: 0 -0.494929 1 1.071804 2 0.721555 3 -0.706771 4 -1.039575 Name: something, dtype: float64 In [35]: s.name Out[35]: 'something' 在许多情况下可以自动分配 ,特别是当从 中选择单个列时,将会被分配列标签。Series nameDataFramename 您可以Series使用该pandas.Series.rename()方法重命名 a。 In [36]: s2 = s.rename("different") In [37]: s2.name Out[37]: 'different' 请注意,s和s2指的是不同的对象。 数据框# DataFrame是一个二维标记数据结构,其中包含可能不同类型的列。您可以将其视为电子表格或 SQL 表,或者 Series 对象的字典。它通常是最常用的 pandas 对象。与 Series 一样,DataFrame 接受许多不同类型的输入: 一维 ndarray、列表、字典或的字典Series 二维 numpy.ndarray 结构化或记录ndarray ASeries 其他DataFrame 除了数据之外,您还可以选择传递索引(行标签)和 列(列标签)参数。如果您传递索引和/或列,则可以保证生成的 DataFrame 的索引和/或列。因此,Series 的字典加上特定索引将丢弃所有与传递的索引不匹配的数据。 如果未传递轴标签,它们将根据常识规则从输入数据构建。 来自系列字典或字典# 生成的索引将是各个系列的索引的并集。如果有任何嵌套字典,它们将首先转换为系列。如果没有传递列,则列将是字典键的有序列表。 In [38]: d = { ....: "one": pd.Series([1.0, 2.0, 3.0], index=["a", "b", "c"]), ....: "two": pd.Series([1.0, 2.0, 3.0, 4.0], index=["a", "b", "c", "d"]), ....: } ....: In [39]: df = pd.DataFrame(d) In [40]: df Out[40]: one two a 1.0 1.0 b 2.0 2.0 c 3.0 3.0 d NaN 4.0 In [41]: pd.DataFrame(d, index=["d", "b", "a"]) Out[41]: one two d NaN 4.0 b 2.0 2.0 a 1.0 1.0 In [42]: pd.DataFrame(d, index=["d", "b", "a"], columns=["two", "three"]) Out[42]: two three d 4.0 NaN b 2.0 NaN a 1.0 NaN 可以通过访问index和columns属性来分别访问行和列标签 : 笔记 当一组特定的列与数据字典一起传递时,传递的列会覆盖字典中的键。 In [43]: df.index Out[43]: Index(['a', 'b', 'c', 'd'], dtype='object') In [44]: df.columns Out[44]: Index(['one', 'two'], dtype='object') 来自 ndarrays / 列表的字典# 所有 ndarray 必须具有相同的长度。如果传递索引,它也必须与数组的长度相同。如果没有传递索引,结果将为range(n),其中n是数组长度。 In [45]: d = {"one": [1.0, 2.0, 3.0, 4.0], "two": [4.0, 3.0, 2.0, 1.0]} In [46]: pd.DataFrame(d) Out[46]: one two 0 1.0 4.0 1 2.0 3.0 2 3.0 2.0 3 4.0 1.0 In [47]: pd.DataFrame(d, index=["a", "b", "c", "d"]) Out[47]: one two a 1.0 4.0 b 2.0 3.0 c 3.0 2.0 d 4.0 1.0 来自结构化或记录数组# 这种情况的处理方式与数组字典相同。 In [48]: data = np.zeros((2,), dtype=[("A", "i4"), ("B", "f4"), ("C", "a10")]) In [49]: data[:] = [(1, 2.0, "Hello"), (2, 3.0, "World")] In [50]: pd.DataFrame(data) Out[50]: A B C 0 1 2.0 b'Hello' 1 2 3.0 b'World' In [51]: pd.DataFrame(data, index=["first", "second"]) Out[51]: A B C first 1 2.0 b'Hello' second 2 3.0 b'World' In [52]: pd.DataFrame(data, columns=["C", "A", "B"]) Out[52]: C A B 0 b'Hello' 1 2.0 1 b'World' 2 3.0 笔记 DataFrame 的工作原理并不像二维 NumPy ndarray。 来自字典列表# In [53]: data2 = [{"a": 1, "b": 2}, {"a": 5, "b": 10, "c": 20}] In [54]: pd.DataFrame(data2) Out[54]: a b c 0 1 2 NaN 1 5 10 20.0 In [55]: pd.DataFrame(data2, index=["first", "second"]) Out[55]: a b c first 1 2 NaN second 5 10 20.0 In [56]: pd.DataFrame(data2, columns=["a", "b"]) Out[56]: a b 0 1 2 1 5 10 来自元组的字典# 您可以通过传递元组字典来自动创建 MultiIndexed 框架。 In [57]: 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}, ....: } ....: ) ....: Out[57]: a b b a c a b A B 1.0 4.0 5.0 8.0 10.0 C 2.0 3.0 6.0 7.0 NaN D NaN NaN NaN NaN 9.0 来自系列# 结果将是一个与输入 Series 具有相同索引的 DataFrame,并且其中一列的名称是 Series 的原始名称(仅当未提供其他列名称时)。 In [58]: ser = pd.Series(range(3), index=list("abc"), name="ser") In [59]: pd.DataFrame(ser) Out[59]: ser a 0 b 1 c 2 来自命名元组列表# namedtuple列表中第一个字段的字段名称决定了DataFrame.剩余的命名元组(或元组)被简单地解压缩,并将它们的值输入到DataFrame.如果这些元组中的任何一个比第一个元组短,namedtuple则相应行中后面的列将被标记为缺失值。如果有一个比第一个长namedtuple,则ValueError引发 a 。 In [60]: from collections import namedtuple In [61]: Point = namedtuple("Point", "x y") In [62]: pd.DataFrame([Point(0, 0), Point(0, 3), (2, 3)]) Out[62]: x y 0 0 0 1 0 3 2 2 3 In [63]: Point3D = namedtuple("Point3D", "x y z") In [64]: pd.DataFrame([Point3D(0, 0, 0), Point3D(0, 3, 5), Point(2, 3)]) Out[64]: x y z 0 0 0 0.0 1 0 3 5.0 2 2 3 NaN 来自数据类列表# PEP557中引入的数据类可以传递到 DataFrame 构造函数中。传递数据类列表相当于传递字典列表。 请注意,列表中的所有值都应该是数据类,列表中的混合类型将导致TypeError. In [65]: from dataclasses import make_dataclass In [66]: Point = make_dataclass("Point", [("x", int), ("y", int)]) In [67]: pd.DataFrame([Point(0, 0), Point(0, 3), Point(2, 3)]) Out[67]: x y 0 0 0 1 0 3 2 2 3 缺失数据 为了构造一个包含缺失数据的 DataFrame,我们使用np.nan来表示缺失值。或者,您可以将 anumpy.MaskedArray 作为数据参数传递给 DataFrame 构造函数,并且其屏蔽条目将被视为丢失。有关详细信息,请参阅缺失数据。 备用构造函数# DataFrame.from_dict DataFrame.from_dict()接受一个字典的字典或一个类似数组序列的字典并返回一个 DataFrame。它的操作类似于DataFrame构造函数,除了默认orient参数之外'columns',但可以设置该参数'index'以便使用字典键作为行标签。 In [68]: pd.DataFrame.from_dict(dict([("A", [1, 2, 3]), ("B", [4, 5, 6])])) Out[68]: A B 0 1 4 1 2 5 2 3 6 如果通过orient='index',键将是行标签。在这种情况下,您还可以传递所需的列名称: In [69]: pd.DataFrame.from_dict( ....: dict([("A", [1, 2, 3]), ("B", [4, 5, 6])]), ....: orient="index", ....: columns=["one", "two", "three"], ....: ) ....: Out[69]: one two three A 1 2 3 B 4 5 6 DataFrame.from_records DataFrame.from_records()接受元组列表或具有结构化数据类型的 ndarray。它的工作方式与普通DataFrame构造函数类似,只是生成的 DataFrame 索引可能是结构化数据类型的特定字段。 In [70]: data Out[70]: array([(1, 2., b'Hello'), (2, 3., b'World')], dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')]) In [71]: pd.DataFrame.from_records(data, index="C") Out[71]: A B C b'Hello' 1 2.0 b'World' 2 3.0 列选择、添加、删除# 您可以DataFrame在语义上将语义视为相似索引Series 对象的字典。获取、设置和删除列的语法与类似的 dict 操作相同: In [72]: df["one"] Out[72]: a 1.0 b 2.0 c 3.0 d NaN Name: one, dtype: float64 In [73]: df["three"] = df["one"] * df["two"] In [74]: df["flag"] = df["one"] > 2 In [75]: df Out[75]: 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 可以像字典一样删除或弹出列: In [76]: del df["two"] In [77]: three = df.pop("three") In [78]: df Out[78]: one flag a 1.0 False b 2.0 False c 3.0 True d NaN False 当插入标量值时,它自然会传播以填充列: In [79]: df["foo"] = "bar" In [80]: df Out[80]: one flag foo a 1.0 False bar b 2.0 False bar c 3.0 True bar d NaN False bar 当插入Series与 不具有相同索引的时DataFrame,它将符合 DataFrame 的索引: In [81]: df["one_trunc"] = df["one"][:2] In [82]: df Out[82]: one flag foo one_trunc a 1.0 False bar 1.0 b 2.0 False bar 2.0 c 3.0 True bar NaN d NaN False bar NaN 您可以插入原始 ndarray,但它们的长度必须与 DataFrame 索引的长度匹配。 默认情况下,列会插入到末尾。DataFrame.insert() 在列中的特定位置插入: In [83]: df.insert(1, "bar", df["one"]) In [84]: df Out[84]: one bar flag foo one_trunc a 1.0 1.0 False bar 1.0 b 2.0 2.0 False bar 2.0 c 3.0 3.0 True bar NaN d NaN NaN False bar NaN 在方法链中分配新列# 受dplyr mutate动词的启发,DataFrame 有一种assign() 方法可以让您轻松创建可能从现有列派生的新列。 In [85]: iris = pd.read_csv("data/iris.data") In [86]: iris.head() Out[86]: SepalLength SepalWidth PetalLength PetalWidth Name 0 5.1 3.5 1.4 0.2 Iris-setosa 1 4.9 3.0 1.4 0.2 Iris-setosa 2 4.7 3.2 1.3 0.2 Iris-setosa 3 4.6 3.1 1.5 0.2 Iris-setosa 4 5.0 3.6 1.4 0.2 Iris-setosa In [87]: iris.assign(sepal_ratio=iris["SepalWidth"] / iris["SepalLength"]).head() Out[87]: SepalLength SepalWidth PetalLength PetalWidth Name sepal_ratio 0 5.1 3.5 1.4 0.2 Iris-setosa 0.686275 1 4.9 3.0 1.4 0.2 Iris-setosa 0.612245 2 4.7 3.2 1.3 0.2 Iris-setosa 0.680851 3 4.6 3.1 1.5 0.2 Iris-setosa 0.673913 4 5.0 3.6 1.4 0.2 Iris-setosa 0.720000 在上面的示例中,我们插入了一个预先计算的值。我们还可以传入一个只有一个参数的函数,以便在分配给的 DataFrame 上进行计算。 In [88]: iris.assign(sepal_ratio=lambda x: (x["SepalWidth"] / x["SepalLength"])).head() Out[88]: SepalLength SepalWidth PetalLength PetalWidth Name sepal_ratio 0 5.1 3.5 1.4 0.2 Iris-setosa 0.686275 1 4.9 3.0 1.4 0.2 Iris-setosa 0.612245 2 4.7 3.2 1.3 0.2 Iris-setosa 0.680851 3 4.6 3.1 1.5 0.2 Iris-setosa 0.673913 4 5.0 3.6 1.4 0.2 Iris-setosa 0.720000 assign() 始终返回数据的副本,保持原始 DataFrame 不变。 当您手头没有对 DataFrame 的引用时,传递可调用对象(而不是要插入的实际值)非常有用。这assign()在操作链中使用时很常见。例如,我们可以将 DataFrame 限制为萼片长度大于 5 的观测值,计算比率并绘制: In [89]: ( ....: iris.query("SepalLength > 5") ....: .assign( ....: SepalRatio=lambda x: x.SepalWidth / x.SepalLength, ....: PetalRatio=lambda x: x.PetalWidth / x.PetalLength, ....: ) ....: .plot(kind="scatter", x="SepalRatio", y="PetalRatio") ....: ) ....: Out[89]: <Axes: xlabel='SepalRatio', ylabel='PetalRatio'> 由于传入了一个函数,因此该函数是在分配给的 DataFrame 上计算的。重要的是,这是已过滤到萼片长度大于 5 的行的 DataFrame。首先进行过滤,然后进行比率计算。在这个示例中,我们没有对可用的已过滤DataFrame 的引用。 的函数签名assign()很简单**kwargs。键是新字段的列名称,值是要插入的值(例如,一个Series或 NumPy 数组),或者是要在DataFrame.返回原始 副本DataFrame,并插入新值。 的顺序**kwargs被保留。这允许依赖赋值,其中稍后的表达式**kwargs可以引用同一assign(). In [90]: dfa = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) In [91]: dfa.assign(C=lambda x: x["A"] + x["B"], D=lambda x: x["A"] + x["C"]) Out[91]: A B C D 0 1 4 5 6 1 2 5 7 9 2 3 6 9 12 在第二个表达式中,x['C']将引用新创建的列,等于。dfa['A'] + dfa['B'] 索引/选择# 索引的基本原理如下: 手术 句法 结果 选择列 df[col] 系列 按标签选择行 df.loc[label] 系列 按整数位置选择行 df.iloc[loc] 系列 切片行 df[5:10] 数据框 通过布尔向量选择行 df[bool_vec] 数据框 例如,行选择返回一个Series,其索引是 的列 DataFrame: In [92]: df.loc["b"] Out[92]: one 2.0 bar 2.0 flag False foo bar one_trunc 2.0 Name: b, dtype: object In [93]: df.iloc[2] Out[93]: one 3.0 bar 3.0 flag True foo bar one_trunc NaN Name: c, dtype: object 有关复杂的基于标签的索引和切片的更详尽的处理,请参阅索引部分。我们将在重新索引部分讨论重新索引/符合新标签集的基础知识 。 数据对齐和算术# DataFrame对象之间的数据对齐会在列和索引(行标签)上自动对齐。同样,生成的对象将具有列标签和行标签的并集。 In [94]: df = pd.DataFrame(np.random.randn(10, 4), columns=["A", "B", "C", "D"]) In [95]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=["A", "B", "C"]) In [96]: df + df2 Out[96]: A B C D 0 0.045691 -0.014138 1.380871 NaN 1 -0.955398 -1.501007 0.037181 NaN 2 -0.662690 1.534833 -0.859691 NaN 3 -2.452949 1.237274 -0.133712 NaN 4 1.414490 1.951676 -2.320422 NaN 5 -0.494922 -1.649727 -1.084601 NaN 6 -1.047551 -0.748572 -0.805479 NaN 7 NaN NaN NaN NaN 8 NaN NaN NaN NaN 9 NaN NaN NaN NaN DataFrame在和之间执行操作时Series,默认行为是对齐列上的索引,从而 按行广播。例如:Series DataFrame In [97]: df - df.iloc[0] Out[97]: A B C D 0 0.000000 0.000000 0.000000 0.000000 1 -1.359261 -0.248717 -0.453372 -1.754659 2 0.253128 0.829678 0.010026 -1.991234 3 -1.311128 0.054325 -1.724913 -1.620544 4 0.573025 1.500742 -0.676070 1.367331 5 -1.741248 0.781993 -1.241620 -2.053136 6 -1.240774 -0.869551 -0.153282 0.000430 7 -0.743894 0.411013 -0.929563 -0.282386 8 -1.194921 1.320690 0.238224 -1.482644 9 2.293786 1.856228 0.773289 -1.446531 有关对匹配和广播行为的显式控制,请参阅灵活的二元运算部分。 标量的算术运算按元素进行: In [98]: df * 5 + 2 Out[98]: A B C D 0 3.359299 -0.124862 4.835102 3.381160 1 -3.437003 -1.368449 2.568242 -5.392133 2 4.624938 4.023526 4.885230 -6.575010 3 -3.196342 0.146766 -3.789461 -4.721559 4 6.224426 7.378849 1.454750 10.217815 5 -5.346940 3.785103 -1.373001 -6.884519 6 -2.844569 -4.472618 4.068691 3.383309 7 -0.360173 1.930201 0.187285 1.969232 8 -2.615303 6.478587 6.026220 -4.032059 9 14.828230 9.156280 8.701544 -3.851494 In [99]: 1 / df Out[99]: A B C D 0 3.678365 -2.353094 1.763605 3.620145 1 -0.919624 -1.484363 8.799067 -0.676395 2 1.904807 2.470934 1.732964 -0.583090 3 -0.962215 -2.697986 -0.863638 -0.743875 4 1.183593 0.929567 -9.170108 0.608434 5 -0.680555 2.800959 -1.482360 -0.562777 6 -1.032084 -0.772485 2.416988 3.614523 7 -2.118489 -71.634509 -2.758294 -162.507295 8 -1.083352 1.116424 1.241860 -0.828904 9 0.389765 0.698687 0.746097 -0.854483 In [100]: df ** 4 Out[100]: A B C D 0 0.005462 3.261689e-02 0.103370 5.822320e-03 1 1.398165 2.059869e-01 0.000167 4.777482e+00 2 0.075962 2.682596e-02 0.110877 8.650845e+00 3 1.166571 1.887302e-02 1.797515 3.265879e+00 4 0.509555 1.339298e+00 0.000141 7.297019e+00 5 4.661717 1.624699e-02 0.207103 9.969092e+00 6 0.881334 2.808277e+00 0.029302 5.858632e-03 7 0.049647 3.797614e-08 0.017276 1.433866e-09 8 0.725974 6.437005e-01 0.420446 2.118275e+00 9 43.329821 4.196326e+00 3.227153 1.875802e+00 布尔运算符也按元素进行操作: In [101]: df1 = pd.DataFrame({"a": [1, 0, 1], "b": [0, 1, 1]}, dtype=bool) In [102]: df2 = pd.DataFrame({"a": [0, 1, 1], "b": [1, 1, 0]}, dtype=bool) In [103]: df1 & df2 Out[103]: a b 0 False False 1 False True 2 True False In [104]: df1 | df2 Out[104]: a b 0 True True 1 True True 2 True True In [105]: df1 ^ df2 Out[105]: a b 0 True True 1 True False 2 False True In [106]: -df1 Out[106]: a b 0 False True 1 True False 2 False False 转置# 要转置,请访问T属性 or DataFrame.transpose(),类似于 ndarray: # only show the first 5 rows In [107]: df[:5].T Out[107]: 0 1 2 3 4 A 0.271860 -1.087401 0.524988 -1.039268 0.844885 B -0.424972 -0.673690 0.404705 -0.370647 1.075770 C 0.567020 0.113648 0.577046 -1.157892 -0.109050 D 0.276232 -1.478427 -1.715002 -1.344312 1.643563 DataFrame 与 NumPy 函数的互操作性# 大多数 NumPy 函数可以直接在Series和上调用DataFrame。 In [108]: np.exp(df) Out[108]: A B C D 0 1.312403 0.653788 1.763006 1.318154 1 0.337092 0.509824 1.120358 0.227996 2 1.690438 1.498861 1.780770 0.179963 3 0.353713 0.690288 0.314148 0.260719 4 2.327710 2.932249 0.896686 5.173571 5 0.230066 1.429065 0.509360 0.169161 6 0.379495 0.274028 1.512461 1.318720 7 0.623732 0.986137 0.695904 0.993865 8 0.397301 2.449092 2.237242 0.299269 9 13.009059 4.183951 3.820223 0.310274 In [109]: np.asarray(df) Out[109]: array([[ 0.2719, -0.425 , 0.567 , 0.2762], [-1.0874, -0.6737, 0.1136, -1.4784], [ 0.525 , 0.4047, 0.577 , -1.715 ], [-1.0393, -0.3706, -1.1579, -1.3443], [ 0.8449, 1.0758, -0.109 , 1.6436], [-1.4694, 0.357 , -0.6746, -1.7769], [-0.9689, -1.2945, 0.4137, 0.2767], [-0.472 , -0.014 , -0.3625, -0.0062], [-0.9231, 0.8957, 0.8052, -1.2064], [ 2.5656, 1.4313, 1.3403, -1.1703]]) DataFrame它并不是 ndarray 的直接替代品,因为它的索引语义和数据模型在某些地方与 n 维数组有很大不同。 Series实现,这使得它可以与 NumPy 的通用函数__array_ufunc__一起使用 。 ufunc 应用于 a 中的底层数组Series。 In [110]: ser = pd.Series([1, 2, 3, 4]) In [111]: np.exp(ser) Out[111]: 0 2.718282 1 7.389056 2 20.085537 3 54.598150 dtype: float64 当多个Series传递给 ufunc 时,它们会在执行操作之前对齐。 与库的其他部分一样,pandas 会自动将带标签的输入作为 ufunc 的一部分与多个输入对齐。例如,numpy.remainder() 在两个Series顺序不同的标签上使用将在操作之前对齐。 In [112]: ser1 = pd.Series([1, 2, 3], index=["a", "b", "c"]) In [113]: ser2 = pd.Series([1, 3, 5], index=["b", "a", "c"]) In [114]: ser1 Out[114]: a 1 b 2 c 3 dtype: int64 In [115]: ser2 Out[115]: b 1 a 3 c 5 dtype: int64 In [116]: np.remainder(ser1, ser2) Out[116]: a 1 b 0 c 3 dtype: int64 像往常一样,取两个索引的并集,并且不重叠的值用缺失值填充。 In [117]: ser3 = pd.Series([2, 4, 6], index=["b", "c", "d"]) In [118]: ser3 Out[118]: b 2 c 4 d 6 dtype: int64 In [119]: np.remainder(ser1, ser3) Out[119]: a NaN b 0.0 c 3.0 d NaN dtype: float64 当二进制 ufunc 应用于 aSeries和时Index,Series 实现优先并Series返回 a。 In [120]: ser = pd.Series([1, 2, 3]) In [121]: idx = pd.Index([4, 5, 6]) In [122]: np.maximum(ser, idx) Out[122]: 0 4 1 5 2 6 dtype: int64 例如, NumPy ufunc 可以安全地应用于Series非 ndarray 数组arrays.SparseArray(请参阅稀疏计算)。如果可能,应用 ufunc 而不将基础数据转换为 ndarray。 控制台显示# 非常大的DataFrame将被截断以在控制台中显示它们。您还可以使用 获得摘要info()。 (棒球数据集来自plyr R包): In [123]: baseball = pd.read_csv("data/baseball.csv") In [124]: print(baseball) id player year stint team lg ... so ibb hbp sh sf gidp 0 88641 womacto01 2006 2 CHN NL ... 4.0 0.0 0.0 3.0 0.0 0.0 1 88643 schilcu01 2006 1 BOS AL ... 1.0 0.0 0.0 0.0 0.0 0.0 .. ... ... ... ... ... .. ... ... ... ... ... ... ... 98 89533 aloumo01 2007 1 NYN NL ... 30.0 5.0 2.0 0.0 3.0 13.0 99 89534 alomasa02 2007 1 NYN NL ... 3.0 0.0 0.0 0.0 0.0 0.0 [100 rows x 23 columns] In [125]: baseball.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 100 entries, 0 to 99 Data columns (total 23 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 id 100 non-null int64 1 player 100 non-null object 2 year 100 non-null int64 3 stint 100 non-null int64 4 team 100 non-null object 5 lg 100 non-null object 6 g 100 non-null int64 7 ab 100 non-null int64 8 r 100 non-null int64 9 h 100 non-null int64 10 X2b 100 non-null int64 11 X3b 100 non-null int64 12 hr 100 non-null int64 13 rbi 100 non-null float64 14 sb 100 non-null float64 15 cs 100 non-null float64 16 bb 100 non-null int64 17 so 100 non-null float64 18 ibb 100 non-null float64 19 hbp 100 non-null float64 20 sh 100 non-null float64 21 sf 100 non-null float64 22 gidp 100 non-null float64 dtypes: float64(9), int64(11), object(3) memory usage: 18.1+ KB 但是,使用DataFrame.to_string()将返回表格形式的字符串表示形式 DataFrame,尽管它并不总是适合控制台宽度: In [126]: print(baseball.iloc[-20:, :12].to_string()) id player year stint team lg g ab r h X2b X3b 80 89474 finlest01 2007 1 COL NL 43 94 9 17 3 0 81 89480 embreal01 2007 1 OAK AL 4 0 0 0 0 0 82 89481 edmonji01 2007 1 SLN NL 117 365 39 92 15 2 83 89482 easleda01 2007 1 NYN NL 76 193 24 54 6 0 84 89489 delgaca01 2007 1 NYN NL 139 538 71 139 30 0 85 89493 cormirh01 2007 1 CIN NL 6 0 0 0 0 0 86 89494 coninje01 2007 2 NYN NL 21 41 2 8 2 0 87 89495 coninje01 2007 1 CIN NL 80 215 23 57 11 1 88 89497 clemero02 2007 1 NYA AL 2 2 0 1 0 0 89 89498 claytro01 2007 2 BOS AL 8 6 1 0 0 0 90 89499 claytro01 2007 1 TOR AL 69 189 23 48 14 0 91 89501 cirilje01 2007 2 ARI NL 28 40 6 8 4 0 92 89502 cirilje01 2007 1 MIN AL 50 153 18 40 9 2 93 89521 bondsba01 2007 1 SFN NL 126 340 75 94 14 0 94 89523 biggicr01 2007 1 HOU NL 141 517 68 130 31 3 95 89525 benitar01 2007 2 FLO NL 34 0 0 0 0 0 96 89526 benitar01 2007 1 SFN NL 19 0 0 0 0 0 97 89530 ausmubr01 2007 1 HOU NL 117 349 38 82 16 3 98 89533 aloumo01 2007 1 NYN NL 87 328 51 112 19 1 99 89534 alomasa02 2007 1 NYN NL 8 22 1 3 1 0 默认情况下,宽数据帧将跨多行打印: In [127]: pd.DataFrame(np.random.randn(3, 12)) Out[127]: 0 1 2 ... 9 10 11 0 -1.226825 0.769804 -1.281247 ... -1.110336 -0.619976 0.149748 1 -0.732339 0.687738 0.176444 ... 1.462696 -1.743161 -0.826591 2 -0.345352 1.314232 0.690579 ... 0.896171 -0.487602 -0.082240 [3 rows x 12 columns] 您可以通过设置选项来更改单行打印的数量display.width : In [128]: pd.set_option("display.width", 40) # default is 80 In [129]: pd.DataFrame(np.random.randn(3, 12)) Out[129]: 0 1 2 ... 9 10 11 0 -2.182937 0.380396 0.084844 ... -0.023688 2.410179 1.450520 1 0.206053 -0.251905 -2.213588 ... -0.025747 -0.988387 0.094055 2 1.262731 1.289997 0.082423 ... -0.281461 0.030711 0.109121 [3 rows x 12 columns] 您可以通过设置来调整各个列的最大宽度display.max_colwidth In [130]: datafile = { .....: "filename": ["filename_01", "filename_02"], .....: "path": [ .....: "media/user_name/storage/folder_01/filename_01", .....: "media/user_name/storage/folder_02/filename_02", .....: ], .....: } .....: In [131]: pd.set_option("display.max_colwidth", 30) In [132]: pd.DataFrame(datafile) Out[132]: filename path 0 filename_01 media/user_name/storage/fo... 1 filename_02 media/user_name/storage/fo... In [133]: pd.set_option("display.max_colwidth", 100) In [134]: pd.DataFrame(datafile) Out[134]: filename path 0 filename_01 media/user_name/storage/folder_01/filename_01 1 filename_02 media/user_name/storage/folder_02/filename_02 您还可以通过选项禁用此功能expand_frame_repr。这会将表格打印在一个块中。 DataFrame 列属性访问和 IPython 补全# 如果DataFrame列标签是有效的 Python 变量名称,则可以像属性一样访问该列: In [135]: df = pd.DataFrame({"foo1": np.random.randn(5), "foo2": np.random.randn(5)}) In [136]: df Out[136]: foo1 foo2 0 1.126203 0.781836 1 -0.977349 -1.071357 2 1.474071 0.441153 3 -0.064034 2.353925 4 -1.282782 0.583787 In [137]: df.foo1 Out[137]: 0 1.126203 1 -0.977349 2 1.474071 3 -0.064034 4 -1.282782 Name: foo1, dtype: float64 这些列还连接到IPython 完成机制,因此可以使用制表符完成: In [5]: df.foo<TAB> # noqa: E225, E999 df.foo1 df.foo2