本节要点:
import pandas as pd import numpy as np
请记住一个基本原则:数据对齐是固有的。除非您明确地这样做,否则标签和数据之间的链接不会断开。
Series是一个一维标签数组,能够保存任何数据类型(整数、字符串、浮点数、Python对象等)。轴标签统称为索引。
创建Series的基本方法是调用:
s = pd.Series(data, index=index)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) /Users/watalo/programs/pandas-note/scripts/用户指南/02-数据结构简介.ipynb Cell 4' in <cell line: 1>() ----> <a href='vscode-notebook-cell:/Users/watalo/programs/pandas-note/scripts/%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97/02-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%AE%80%E4%BB%8B.ipynb#ch0000003?line=0'>1</a> s = pd.Series(data, index=index) NameError: name 'data' is not defined
data,可以有很多种:
index,轴标签列表。可以分几种情况:
s = pd.Series(np.random.randn(5),index=['a', 'b','c','d','e']) s
a 0.883299 b -1.978170 c 0.563257 d -0.797373 e 0.776716 dtype: float64
s.index
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
Note:
- pandas支持非唯一索引值。如果试图执行不支持重复索引值的操作,将会引发异常。原因主要是基于性能的考虑(在计算中有许多实例,比如GroupBy的某些部分,其中不使用索引)。
Series可以直接从字典实例化
d = { 'a':1, 'b':2, 'c':3, } s = pd.Series(d) s
a 1 b 2 c 3 dtype: int64
当数据是dict,并且没有传递索引时,如果您使用的是Python版本> = 3.6和pandas版本> = 0.23,系列索引将按照dict的插入顺序排序。
如果您使用的是Python < 3.6或pandas < 0.23,并且没有传递索引,那么系列索引将是字典键的词汇排序列表。
如果传递了一个索引,则对应于索引中标签的数据中的值将被取出。
s = pd.Series(d, index=['e','d','c','b','a']) s
e NaN d NaN c 3.0 b 2.0 a 1.0 dtype: float64
如果数据是标量值,则必须提供索引。该值将重复以匹配索引的长度。
s = pd.Series(5, index=['1','2','3','4','5','6']) s.index
Index(['1', '2', '3', '4', '5', '6'], dtype='object')
Series的行为非常类似于ndarray,并且是大多数NumPy函数的有效参数。但是,切片等操作也会对索引进行切片。
s[0]
0.8832993937192529
s[:3]
a 0.883299 b -1.978170 c 0.563257 dtype: float64
s[s > s.median()]
a 0.883299 e 0.776716 dtype: float64
s[[3,1]]
d -0.797373 b -1.978170 dtype: float64
np.exp(s) # e^s 自然数的幂
a 2.418867 b 0.138322 c 1.756384 d 0.450511 e 2.174320 dtype: float64
s.dtype
dtype('float64')
这是Numpy的数据类型。然而,pandas和第三方库在一些地方扩展了NumPy的类型系统,在这种情况下,dtype将是ExtensionDtype。pandas中的一些例子是分类数据和可空整数数据类型。有关更多信息,请参见dtypes。
如果您需要获取一个Series的实际数组,请使用Series.array。
s.array
<PandasArray> [ 0.8832993937192529, -1.978169783141144, 0.563257208682096, -0.7973732860782697, 0.7767158700697264] Length: 5, dtype: float64
当您需要在没有索引的情况下执行某些操作时(例如,禁用自动对齐),访问数组会很有用。
Series.array将始终是ExtensionArray。简而言之,ExtensionArray是一个或多个具体数组(如numpy.ndarray)的简单包装。pandas知道如何获取ExtensionArray并将其存储在数据帧的一个系列或一列中。有关更多信息,请参见dtypes。
虽然Series类似于ndarray,但如果需要实际的ndarray,则使用Series.to_numpy()。
s.to_numpy()
array([ 0.88329939, -1.97816978, 0.56325721, -0.79737329, 0.77671587])
即使序列是ExtensionArray类型的,Series.to_numpy()也将返回NumPy ndarray。
系列类似于固定大小的字典,因为您可以通过索引标签获取和设置值:
s['a']
0.8832993937192529
s['f'] = 12.0 s
a 0.883299 b -1.978170 c 0.563257 d -0.797373 e 0.776716 f 12.000000 dtype: float64
'e' in s
True
'g' in s
False
s.get('s')
使用get方法,缺少的标签将返回None或指定的默认值:
s.get('s', np.nan)
nan
当处理原始NumPy数组时,通常没有必要逐值循环。在pandas中处理系列时也是如此。Series也可以传递给大多数需要ndarray的NumPy方法。
s+s
a 1.766599 b -3.956340 c 1.126514 d -1.594747 e 1.553432 f 24.000000 dtype: float64
s *2
a 1.766599 b -3.956340 c 1.126514 d -1.594747 e 1.553432 f 24.000000 dtype: float64
np.exp(s)
a 2.418867 b 0.138322 c 1.756384 d 0.450511 e 2.174320 f 162754.791419 dtype: float64
Series和ndarray之间的一个关键区别是,Series之间的操作会根据标签自动对齐数据。因此,您可以在编写计算时不考虑所涉及的系列是否具有相同的标签。
s[1:] + s[:-1]
a NaN b -3.956340 c 1.126514 d -1.594747 e 1.553432 f NaN dtype: float64
(s[1:] + s[:-1]).dropna()
b -3.956340 c 1.126514 d -1.594747 e 1.553432 dtype: float64
未对齐系列之间的运算结果将包含相关索引的并集。如果在一个系列或另一个系列中找不到标签,结果将被标记为缺少NaN。能够在不进行任何显式数据对齐的情况下编写代码,这为交互式数据分析和研究提供了极大的自由和灵活性。pandas数据结构的集成数据对齐特性使pandas有别于大多数处理标注数据的相关工具。
注意:
一般来说,我们选择让不同索引对象之间的默认操作结果产生索引的联合,以避免信息丢失。尽管缺少数据,但作为计算的一部分,具有索引标签通> 常是重要的信息。当然,您可以选择通过dropna函数删除带有缺失数据的标签。
系列也可以有名称属性:
ss = pd.Series(np.random.randn(5), name = 'Something') ss
0 0.854195 1 -2.466692 2 -1.145952 3 -0.192568 4 0.160081 Name: Something, dtype: float64
在许多情况下,将自动分配系列名称,尤其是在处理DataFrame的一维切片时,如下所示。
你可以给Series重新命名。Series.rename()方法。
s2 = ss.rename('nothing') s2.name
'nothing'
DataFrame是每列数据带有潜在不同类型的二维标记数据结构。你可以把它想象成一个电子表格或SQL表,或者一系列对象的字典。它是pandas最常用的对象。像Series一样,DataFrame接受许多不同类型的输入:
除了数据,您还可以选择传递索引(行标签)和列(列标签)参数。如果您传递一个索引和/或列,您就保证了结果数据帧的索引和/或列。因此,一个系列字典加上一个特定的索引将丢弃所有与传递的索引不匹配的数据。
如果没有传递轴标签,它们将根据常识规则从输入数据中构建。(0,1,2,3,4,5)
注意:
当数据是一个dict,并且没有指定columns时,如果您使用的是Python版本> = 3.6和pandas >= 0.23,DataFrame列将按dict的插入顺序排序。
如果您使用的是Python < 3.6或pandas < 0.23,并且没有指定columns,DataFrame列将是字典键的词汇排序列表。
生成的索引将是各种系列指数的联合。如果有任何嵌套的字典,它们将首先被转换成序列。如果没有传递任何列,这些列将是dict键的有序列表。
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']), } df = pd.DataFrame(d) df
one | two | |
---|---|---|
a | 1.0 | 1.0 |
b | 2.0 | 2.0 |
c | 3.0 | 3.0 |
d | NaN | 4.0 |
pd.DataFrame(d, index=['a','b','c'])
one | two | |
---|---|---|
a | 1.0 | 1.0 |
b | 2.0 | 2.0 |
c | 3.0 | 3.0 |
pd.DataFrame(d, index=["d", "b", "a"], columns=["two", "three"])
two | three | |
---|---|---|
d | 4.0 | NaN |
b | 2.0 | NaN |
a | 1.0 | NaN |
通过访问索引和列属性,可以分别访问行标签和列标签:
注意
当一组特定的列和一个数据字典一起传递时,传递的列会覆盖字典中的键。
df.index
Index(['a', 'b', 'c', 'd'], dtype='object')
df.columns
Index(['one', 'two'], dtype='object')
多维数组的长度必须相同。如果传递一个索引,它显然也必须与数组的长度相同。如果没有传递索引,结果将是range(n),其中n是数组长度。
d = {"one": [1.0, 2.0, 3.0, 4.0], "two": [4.0, 3.0, 2.0, 1.0]} pd.DataFrame(d)
one | two | |
---|---|---|
0 | 1.0 | 4.0 |
1 | 2.0 | 3.0 |
2 | 3.0 | 2.0 |
3 | 4.0 | 1.0 |
pd.DataFrame(d, index=list('abcd'))
one | two | |
---|---|---|
a | 1.0 | 4.0 |
b | 2.0 | 3.0 |
c | 3.0 | 2.0 |
d | 4.0 | 1.0 |
这种情况的处理方式与数组字典相同。
data = np.zeros((2,),dtype = [("A", "i4"),("B", "f4"),("C", "a10")]) data[:] = [(1, 2.0, "Hello"),(2, 3.0, "World")] pd.DataFrame(data)
A | B | C | |
---|---|---|---|
0 | 1 | 2.0 | b'Hello' |
1 | 2 | 3.0 | b'World' |
pd.DataFrame(data, index=['first','second'])
A | B | C | |
---|---|---|---|
first | 1 | 2.0 | b'Hello' |
second | 2 | 3.0 | b'World' |
pd.DataFrame(data, columns=['C', "A","B"])
C | A | B | |
---|---|---|---|
0 | b'Hello' | 1 | 2.0 |
1 | b'World' | 2 | 3.0 |
注意:
DataFrame的工作方式并不完全像二维NumPy ndarray。
data2 = [{"a": 1, "b": 2}, {"a": 5, "b": 10, "c": 20}] pd.DataFrame(data2)
a | b | c | |
---|---|---|---|
0 | 1 | 2 | NaN |
1 | 5 | 10 | 20.0 |
pd.DataFrame(data2, index=["first", "second"])
a | b | c | |
---|---|---|---|
first | 1 | 2 | NaN |
second | 5 | 10 | 20.0 |
pd.DataFrame(data2, columns=["a", "b"])
a | b | |
---|---|---|
0 | 1 | 2 |
1 | 5 | 10 |
通过传递元组字典,可以自动创建多索引框架。
pd.DataFrame( { ("a", "b"): {("A", "B"): 1, ("A", "C"): 2}, ("a", "a"): {("A", "C"): 3, ("A", "B"): 4}, ("a", "c"): {("B", "B"): 5, ("A", "C"): 6}, ("b", "a"): {("B", "C"): 7, ("A", "B"): 8}, ("b", "b"): {("A", "D"): 9, ("A", "B"): 10}, } )
a | b | |||||
---|---|---|---|---|---|---|
b | a | c | a | b | ||
A | B | 1.0 | 4.0 | NaN | 8.0 | 10.0 |
C | 2.0 | 3.0 | 6.0 | NaN | NaN | |
B | B | NaN | NaN | 5.0 | NaN | NaN |
C | NaN | NaN | NaN | 7.0 | NaN | |
A | D | NaN | NaN | NaN | NaN | 9.0 |
结果将是一个DataFrame,其索引与输入序列相同,并且有一个列的名称是序列的原始名称(仅当没有提供其他列名称时)。
列表中第一个命名元组的字段名称决定了DataFrame的列。剩余的命名元组(或元组)被简单地解包,并且它们的值被赋值到数据帧的行中。如果这些元组中的任何一个比第一个命名元组短,则相应行中后面的列将被标记为缺失值。如果有任何长度超过第一个命名的元组,将引发ValueError。
from collections import namedtuple Point = namedtuple("Point",'x y') pd.DataFrame([Point(0, 0),Point(0,2),(2,3)])
x | y | |
---|---|---|
0 | 0 | 0 |
1 | 0 | 2 |
2 | 2 | 3 |
Point3D = namedtuple("Point3D",'x y z') pd.DataFrame([Point3D(0,0,0),Point3D(0,3,5),Point(0,2)])
x | y | z | |
---|---|---|---|
0 | 0 | 0 | 0.0 |
1 | 0 | 3 | 5.0 |
2 | 0 | 2 | NaN |
版本1.1.0中的新增功能。
PEP557中介绍的数据类可以传递给DataFrame构造函数。传递数据类列表相当于传递字典列表。
请注意,列表中的所有值都应该是数据类,混合列表中的类型会导致类型错误。
from dataclasses import make_dataclass Point = make_dataclass("Point", [("x", int), ("y", int)]) pd.DataFrame([Point(0, 0), Point(0, 3), Point(2, 3)])
x | y | |
---|---|---|
0 | 0 | 0 |
1 | 0 | 3 |
2 | 2 | 3 |
关于这个主题,我们将在“缺失数据”部分详细讨论。为了构造一个带有缺失数据的DataFrame,我们使用np.nan来表示缺失值。或者,你可以通过一个numpy.MaskedArray作为DataFrame构造函数的数据参数,其被屏蔽的条目将被视为丢失。
DataFrame.from_dict接受一个dict或一个类似数组的序列的dict,并返回一个DataFrame。除了orient参数之外,它的操作与DataFrame构造函数类似,orient参数默认为“columns ”,但可以设置为“index ”,以便将dict键用作行标签。
pd.DataFrame.from_dict(dict([("A", [1, 2, 3]), ("B", [4, 5, 6])]))
A | B | |
---|---|---|
0 | 1 | 4 |
1 | 2 | 5 |
2 | 3 | 6 |
如果传递orient='index ',则键将是行标签。在这种情况下,您还可以传递所需的列名:
pd.DataFrame.from_dict( dict([("A", [1, 2, 3]), ("B", [4, 5, 6])]), orient="index", columns=["one", "two", "three"], )
one | two | three | |
---|---|---|---|
A | 1 | 2 | 3 |
B | 4 | 5 | 6 |
DataFrame.from_records采用元组列表或具有结构化数据类型的ndarray。它的工作方式类似于普通的DataFrame构造函数,只是产生的DataFrame索引可能是结构化数据类型的特定字段。例如:
from_dicts
,from_records
这两个函数不知道什么意义。
您可以将DataFrame在语义上视为相似索引系列对象的字典。获取、设置和删除列的语法与类似的dict操作相同:
d = { 'one': pd.Series([1,2,3],index=list('abc')), 'two': pd.Series([1,2,3,4],index=list('abcd')) } df =pd.DataFrame(d) df
one | two | |
---|---|---|
a | 1.0 | 1 |
b | 2.0 | 2 |
c | 3.0 | 3 |
d | NaN | 4 |
df['one']
a 1.0 b 2.0 c 3.0 d NaN Name: one, dtype: float64
df['three'] = df['one']*df['two'] df['three']
a 1.0 b 4.0 c 9.0 d NaN Name: three, dtype: float64
df['flag'] = df['two'] > 2 df['flag']
a False b False c True d True Name: flag, dtype: bool
可以像使用字典一样删除或弹出列:
del df['two'] df.pop('three') df
one | flag | |
---|---|---|
a | 1.0 | False |
b | 2.0 | False |
c | 3.0 | True |
d | NaN | True |
当插入标量值时,它将自然地传播(繁殖)以填充列:
df['foo'] = 'bar' df
one | flag | foo | |
---|---|---|---|
a | 1.0 | False | bar |
b | 2.0 | False | bar |
c | 3.0 | True | bar |
d | NaN | True | bar |
当插入与DataFrame没有相同索引的序列时,它将符合DataFrame的索引:
df['one_trunc']= df['one'][:2] df
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 | True | bar | NaN |
您可以插入原始ndarrays,但它们的长度必须与DataFarme索引的长度相匹配。
raw ndarrays:是不是构造Series的ndarrays? 而Series在DataFrame中就是列,所以索引必须保持一致。
注意:Series在DataFrame中不是row的概念,而是与索引对应的。
默认情况下,列在末尾插入。插入功能可用于在列中的特定位置插入:
df.insert(1, 'bar', df['one']) df
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 | True | bar | NaN |
array = df['one'].to_numpy()
array
array([ 1., 2., 3., nan])
df.insert(1,'one_array',array) df
one | one_array | bar | flag | foo | one_trunc | |
---|---|---|---|---|---|---|
a | 1.0 | 1.0 | 1.0 | False | bar | 1.0 |
b | 2.0 | 2.0 | 2.0 | False | bar | 2.0 |
c | 3.0 | 3.0 | 3.0 | True | bar | NaN |
d | NaN | NaN | NaN | True | bar | NaN |
DataFrame.assign()方法,允许您能轻松地从现有列派生新列。
iris = pd.read_csv("./data/iris.csv") # 这些数据没有直接提供,但是可以使用sklearn库获得,见irisdata.py iris.head()
Unnamed: 0 | sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | outcome | |
---|---|---|---|---|---|---|
0 | 0 | 5.1 | 3.5 | 1.4 | 0.2 | 0 |
1 | 1 | 4.9 | 3.0 | 1.4 | 0.2 | 0 |
2 | 2 | 4.7 | 3.2 | 1.3 | 0.2 | 0 |
3 | 3 | 4.6 | 3.1 | 1.5 | 0.2 | 0 |
4 | 4 | 5.0 | 3.6 | 1.4 | 0.2 | 0 |
iris.columns # 数据下载后有点不一样,做一些处理 iris.pop('Unnamed: 0')
iris= iris.rename(columns={ "sepal length (cm)": "Sepallength", "sepal width (cm)":"Sepalwidth", "petal length (cm)":"Petallength", "petal width (cm)":"Petalwidth", }) iris
Sepallength | Sepalwidth | Petallength | Petalwidth | outcome | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | 0 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | 0 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | 0 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | 0 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | 0 |
... | ... | ... | ... | ... | ... |
145 | 6.7 | 3.0 | 5.2 | 2.3 | 2 |
146 | 6.3 | 2.5 | 5.0 | 1.9 | 2 |
147 | 6.5 | 3.0 | 5.2 | 2.0 | 2 |
148 | 6.2 | 3.4 | 5.4 | 2.3 | 2 |
149 | 5.9 | 3.0 | 5.1 | 1.8 | 2 |
150 rows × 5 columns
assign总是返回数据的副本,而不改变原始数据帧。
当您手头没有对DataFrame的引用时,传递一个callable(而不是要插入的实际值)非常有用。在操作链中使用赋值时,这很常见。例如,我们可以将数据框限制为萼片长度大于5的观察值,计算比率,并绘制:
( 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") )
<AxesSubplot:xlabel='SepalRatio', ylabel='PetalRatio'>
因为函数是传入的,所以函数是在被赋值的DataFrame上计算的。重要的是,这是已经被过滤成萼片长度大于5的那些行的DataFrame。首先进行过滤,然后进行比率计算。这是一个我们没有可用的过滤数据帧参考的例子。
用于赋值的函数符号就是**kwargs。键是新字段的列名,值或者是要插入的值(例如,Series或NumPy数组),或者是要在DataFrame上调用的一个参数的函数。返回原始DataFrame的副本,并插入新值。
从Python 3.6开始,保留了kwargs的顺序。这允许依赖赋值,其中kwargs中后面的表达式可以引用同一个assign()中前面创建的列。
dfa = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) dfa.assign(C = lambda x: x['A']+x['B'], D = lambda x: x['C']+x['B'])
A | B | C | D | |
---|---|---|---|---|
0 | 1 | 4 | 5 | 9 |
1 | 2 | 5 | 7 | 12 |
2 | 3 | 6 | 9 | 15 |
在第二个表达式中,x['C']
将引用新创建的列,等于dfa['A'] + dfa['B']
。
索引的基本语法如下:
操作 | 语法 | 结果 |
---|---|---|
选择列 | df[col] |
Series |
选择行,按标签 | df.loc[label] |
Series |
选择行,按位置 | df.iloc[loc] |
Series |
行切片 | df[5:10] |
DataFrame |
选择行,按布尔向量 | df[bool_vec] |
DataFrame |
例如,行选择返回一个系列,其索引是数据帧的列:
df.loc['b']
one 2.0 bar 2.0 flag False foo bar one_trunc 2.0 Name: b, dtype: object
df.iloc[2]
one 3.0 bar 3.0 flag True foo bar one_trunc NaN Name: c, dtype: object
有关复杂的基于标签的索引和切片的更详尽的论述,请参阅索引一节。我们将在重建索引一节中讨论重建索引/符合新标签集的基础知识。
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
A | B | C | D | |
---|---|---|---|---|
0 | 0.791989 | 1.341828 | -1.053359 | NaN |
1 | -2.860043 | -0.651756 | 0.968590 | NaN |
2 | 0.302202 | 0.969432 | 2.437236 | NaN |
3 | 0.041251 | -0.674415 | -1.176100 | NaN |
4 | 1.280775 | -3.399843 | -0.261751 | NaN |
5 | -0.461997 | 0.362092 | -1.414859 | NaN |
6 | -0.673482 | 0.729642 | -0.105722 | NaN |
7 | NaN | NaN | NaN | NaN |
8 | NaN | NaN | NaN | NaN |
9 | NaN | NaN | NaN | NaN |
在DataFrame和Series之间执行操作时,默认行为是对齐DataFrame列上的Series索引,从而按行扩充。例如:
df - df.iloc[0]
A | B | C | D | |
---|---|---|---|---|
0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
1 | -0.259708 | -1.257956 | 0.955413 | 0.560935 |
2 | 0.810066 | 0.324911 | 0.091001 | 0.314986 |
3 | 0.947707 | -1.684121 | -1.993186 | -0.596684 |
4 | 0.541464 | -2.169467 | -1.123502 | 1.075880 |
5 | 0.549983 | -0.153812 | -1.049392 | 0.629938 |
6 | 0.088894 | 0.149594 | -0.015635 | -0.086467 |
7 | 0.872696 | -2.982769 | 1.441553 | 0.484981 |
8 | 0.849373 | -1.689104 | -2.110944 | -0.674473 |
9 | 0.605957 | -0.396698 | -1.618992 | 1.284446 |
对于匹配和广播行为的显式控制,请参见灵活二进制操作一节。
标量操作正如您所料:
df * 5 + 2
A | B | C | D | |
---|---|---|---|---|
0 | 1.323638 | 6.561460 | 3.348269 | -0.735045 |
1 | 0.025100 | 0.271678 | 8.125334 | 2.069632 |
2 | 5.373969 | 8.186013 | 3.803276 | 0.839885 |
3 | 6.062174 | -1.859145 | -6.617663 | -3.718466 |
4 | 4.030958 | -4.285874 | -2.269242 | 4.644356 |
5 | 4.073552 | 5.792401 | -1.898691 | 2.414645 |
6 | 1.768109 | 7.309428 | 3.270094 | -1.167379 |
7 | 5.687115 | -8.352386 | 10.556034 | 1.689860 |
8 | 5.570503 | -1.884063 | -7.206450 | -4.107409 |
9 | 4.353421 | 4.577971 | -4.746690 | 5.687187 |
1/df
A | B | C | D | |
---|---|---|---|---|
0 | -7.392487 | 1.096140 | 3.708458 | -1.828124 |
1 | -2.531773 | -2.892979 | 0.816282 | 71.806529 |
2 | 1.481934 | 0.808275 | 2.772731 | -4.309916 |
3 | 1.230868 | -1.295624 | -0.580204 | -0.874360 |
4 | 2.461892 | -0.795434 | -1.171168 | 1.890820 |
5 | 2.411322 | 1.318426 | -1.282482 | 12.058512 |
6 | -21.561889 | 0.941721 | 3.936717 | -1.578592 |
7 | 1.356074 | -0.482980 | 0.584383 | -16.121743 |
8 | 1.400363 | -1.287312 | -0.543098 | -0.818678 |
9 | 2.124567 | 1.939510 | -0.741104 | 1.356047 |
df ** 4
A | B | C | D | |
---|---|---|---|---|
0 | 0.000335 | 0.692684 | 0.005287 | 8.953187e-02 |
1 | 0.024339 | 0.014276 | 2.252367 | 3.761355e-08 |
2 | 0.207341 | 2.342952 | 0.016919 | 2.898175e-03 |
3 | 0.435666 | 0.354882 | 8.824253 | 1.710954e+00 |
4 | 0.027222 | 2.497943 | 0.531524 | 7.823474e-02 |
5 | 0.029579 | 0.330961 | 0.369654 | 4.729607e-05 |
6 | 0.000005 | 1.271484 | 0.004164 | 1.610350e-01 |
7 | 0.295711 | 18.377304 | 8.574522 | 1.480308e-05 |
8 | 0.260039 | 0.364137 | 11.494463 | 2.226118e+00 |
9 | 0.049082 | 0.070669 | 3.314996 | 2.957336e-01 |
布尔运算符也起作用:
df1 = pd.DataFrame({"a": [1, 0, 1], "b": [0, 1, 1]}, dtype=bool) df2 = pd.DataFrame({"a": [0, 1, 1], "b": [1, 1, 0]}, dtype=bool) df1 & df2
a | b | |
---|---|---|
0 | False | False |
1 | False | True |
2 | True | False |
df1 | df2
a | b | |
---|---|---|
0 | True | True |
1 | True | True |
2 | True | True |
df1 ^ df2
a | b | |
---|---|---|
0 | True | True |
1 | True | False |
2 | False | True |
-df1
a | b | |
---|---|---|
0 | False | True |
1 | True | False |
2 | False | False |
要转置,访问T属性(也是转置函数),类似于ndarray:
df[:5].T
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
A | -0.135272 | -0.394980 | 0.674794 | 0.812435 | 0.406192 |
B | 0.912292 | -0.345664 | 1.237203 | -0.771829 | -1.257175 |
C | 0.269654 | 1.225067 | 0.360655 | -1.723533 | -0.853848 |
D | -0.547009 | 0.013926 | -0.232023 | -1.143693 | 0.528871 |
Elementwise NumPy ufuncs (log、exp、sqrt、…)和各种其他NumPy函数可以在Series和DataFrame上使用,不会出现任何问题,前提是其中的数据是数字:
np.exp(df)
A | B | C | D | |
---|---|---|---|---|
0 | 0.873478 | 2.490023 | 1.309511 | 0.578678 |
1 | 0.673693 | 0.707750 | 3.404394 | 1.014024 |
2 | 1.963628 | 3.445960 | 1.434269 | 0.792928 |
3 | 2.253388 | 0.462167 | 0.178435 | 0.318640 |
4 | 1.501090 | 0.284457 | 0.425773 | 1.697016 |
5 | 1.513932 | 2.135029 | 0.458526 | 1.086465 |
6 | 0.954681 | 2.891819 | 1.289196 | 0.530744 |
7 | 2.090541 | 0.126126 | 5.535637 | 0.939857 |
8 | 2.042349 | 0.459869 | 0.158613 | 0.294793 |
9 | 1.601089 | 1.674633 | 0.259412 | 2.090571 |
np.asarray(df)
array([[-0.13527247, 0.91229194, 0.26965386, -0.54700892], [-0.39498006, -0.34566449, 1.22506688, 0.01392631], [ 0.67479376, 1.23720267, 0.36065521, -0.23202306], [ 0.81243481, -0.77182897, -1.72353255, -1.14369325], [ 0.4061916 , -1.25717476, -0.85384845, 0.5288712 ], [ 0.41471035, 0.75848022, -0.77973825, 0.08292897], [-0.04637813, 1.06188561, 0.25401878, -0.63347584], [ 0.73742305, -2.07047719, 1.71120672, -0.06202803], [ 0.7141007 , -0.77681254, -1.84128991, -1.22148186], [ 0.47068421, 0.51559416, -1.34933804, 0.7374374 ]])
DataFrame不是ndarray的替代品,因为它的索引语义和数据模型与n维数组有很大不同。
Series实现了__array_ufunc__,这允许它与NumPy的通用函数一起工作。
ufunc应用于系列中的基础数组。
ser = pd.Series([1,2,3,4]) np.exp(ser)
0 2.718282 1 7.389056 2 20.085537 3 54.598150 dtype: float64
像库的其他部分一样,pandas将自动对齐带标签的输入,作为具有多个输入的ufunc的一部分。例如,对具有不同排序标签的两个系列使用numpy.remainder()将在操作之前对齐。
ser1 = pd.Series([1, 2, 3], index=["a", "b", "c"]) ser2 = pd.Series([1, 3, 5], index=["b", "a", "c"]) ser1, ser2
(a 1 b 2 c 3 dtype: int64, b 1 a 3 c 5 dtype: int64)
np.remainder(ser1, ser2)
a 1 b 0 c 3 dtype: int64
像往常一样,取两个索引的并集,用缺失值填充不重叠的值。
ser3 = pd.Series([2, 4, 6], index=["b", "c", "d"]) ser3
b 2 c 4 d 6 dtype: int64
np.remainder(ser1, ser3)
a NaN b 0.0 c 3.0 d NaN dtype: float64
当二进制ufunc应用于序列和索引时,序列实现优先,并返回一个序列。
ser = pd.Series([1, 2, 3]) idx = pd.Index([4, 5, 6]) np.maximum(ser, idx)
0 4 1 5 2 6 dtype: int64
NumPy ufuncs可以安全地应用于非ndarray数组支持的系列,例如arrays.SparseArray(请参见Sparse calculation)。如果可能,在不将基础数据转换为ndarray的情况下应用ufunc。
非常大的DataFrame将被截断以显示在控制台中。您还可以使用info()获得摘要。(这里我正在阅读来自plyr R包的棒球数据集的CSV版本):
baseball = pd.read_csv("./data/baseball.csv") print(baseball)
Unnamed: 0 id year stint team lg g ab r h ... \ 0 4 ansonca01 1871 1 RC1 NaN 25 120 29 39 ... 1 44 forceda01 1871 1 WS3 NaN 32 162 45 45 ... 2 68 mathebo01 1871 1 FW1 NaN 19 89 15 24 ... 3 99 startjo01 1871 1 NY2 NaN 33 161 35 58 ... 4 102 suttoez01 1871 1 CL1 NaN 29 128 35 45 ... ... ... ... ... ... ... ... ... ... .. ... ... 21694 89525 benitar01 2007 2 FLO NL 34 0 0 0 ... 21695 89526 benitar01 2007 1 SFN NL 19 0 0 0 ... 21696 89530 ausmubr01 2007 1 HOU NL 117 349 38 82 ... 21697 89533 aloumo01 2007 1 NYN NL 87 328 51 112 ... 21698 89534 alomasa02 2007 1 NYN NL 8 22 1 3 ... rbi sb cs bb so ibb hbp sh sf gidp 0 16.0 6.0 2.0 2 1.0 NaN NaN NaN NaN NaN 1 29.0 8.0 0.0 4 0.0 NaN NaN NaN NaN NaN 2 10.0 2.0 1.0 2 0.0 NaN NaN NaN NaN NaN 3 34.0 4.0 2.0 3 0.0 NaN NaN NaN NaN NaN 4 23.0 3.0 1.0 1 0.0 NaN NaN NaN NaN NaN ... ... ... ... .. ... ... ... ... ... ... 21694 0.0 0.0 0.0 0 0.0 0.0 0.0 0.0 0.0 0.0 21695 0.0 0.0 0.0 0 0.0 0.0 0.0 0.0 0.0 0.0 21696 25.0 6.0 1.0 37 74.0 3.0 6.0 4.0 1.0 11.0 21697 49.0 3.0 0.0 27 30.0 5.0 2.0 0.0 3.0 13.0 21698 0.0 0.0 0.0 0 3.0 0.0 0.0 0.0 0.0 0.0 [21699 rows x 23 columns]
baseball.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 21699 entries, 0 to 21698 Data columns (total 23 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Unnamed: 0 21699 non-null int64 1 id 21699 non-null object 2 year 21699 non-null int64 3 stint 21699 non-null int64 4 team 21699 non-null object 5 lg 21634 non-null object 6 g 21699 non-null int64 7 ab 21699 non-null int64 8 r 21699 non-null int64 9 h 21699 non-null int64 10 X2b 21699 non-null int64 11 X3b 21699 non-null int64 12 hr 21699 non-null int64 13 rbi 21687 non-null float64 14 sb 21449 non-null float64 15 cs 17174 non-null float64 16 bb 21699 non-null int64 17 so 20394 non-null float64 18 ibb 14171 non-null float64 19 hbp 21322 non-null float64 20 sh 20739 non-null float64 21 sf 14309 non-null float64 22 gidp 16427 non-null float64 dtypes: float64(9), int64(11), object(3) memory usage: 3.8+ MB
但是,使用to_string将以表格形式返回DataFrame的字符串表示形式,尽管它并不总是适合控制台宽度:
print(baseball.iloc[-20:,:12].to_string())
Unnamed: 0 id year stint team lg g ab r h X2b X3b 21679 89474 finlest01 2007 1 COL NL 43 94 9 17 3 0 21680 89480 embreal01 2007 1 OAK AL 4 0 0 0 0 0 21681 89481 edmonji01 2007 1 SLN NL 117 365 39 92 15 2 21682 89482 easleda01 2007 1 NYN NL 76 193 24 54 6 0 21683 89489 delgaca01 2007 1 NYN NL 139 538 71 139 30 0 21684 89493 cormirh01 2007 1 CIN NL 6 0 0 0 0 0 21685 89494 coninje01 2007 2 NYN NL 21 41 2 8 2 0 21686 89495 coninje01 2007 1 CIN NL 80 215 23 57 11 1 21687 89497 clemero02 2007 1 NYA AL 2 2 0 1 0 0 21688 89498 claytro01 2007 2 BOS AL 8 6 1 0 0 0 21689 89499 claytro01 2007 1 TOR AL 69 189 23 48 14 0 21690 89501 cirilje01 2007 2 ARI NL 28 40 6 8 4 0 21691 89502 cirilje01 2007 1 MIN AL 50 153 18 40 9 2 21692 89521 bondsba01 2007 1 SFN NL 126 340 75 94 14 0 21693 89523 biggicr01 2007 1 HOU NL 141 517 68 130 31 3 21694 89525 benitar01 2007 2 FLO NL 34 0 0 0 0 0 21695 89526 benitar01 2007 1 SFN NL 19 0 0 0 0 0 21696 89530 ausmubr01 2007 1 HOU NL 117 349 38 82 16 3 21697 89533 aloumo01 2007 1 NYN NL 87 328 51 112 19 1 21698 89534 alomasa02 2007 1 NYN NL 8 22 1 3 1 0
默认情况下,将跨多行打印ames:
pd.DataFrame(np.random.randn(3, 12))
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.417027 | -0.662031 | 0.217932 | 0.180797 | 1.995120 | 1.281095 | -2.085882 | 0.416237 | -1.994071 | -0.890021 | 0.143770 | 1.171460 |
1 | -1.453006 | -0.495643 | 0.861393 | 0.297495 | -1.656289 | 1.218641 | -1.247598 | 2.480623 | -2.064665 | -0.365235 | 0.302656 | 1.092608 |
2 | -2.301177 | -0.419567 | 1.743266 | -0.342251 | -0.157273 | 0.086404 | 1.237279 | 0.540404 | 0.076418 | -0.256506 | -0.010054 | -1.135659 |
您可以通过设置display.width选项来更改单行打印量:
pd.set_option("display.width", 20) # default is 80 pd.DataFrame(np.random.randn(3, 10))
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | -0.108353 | -1.836611 | 0.394449 | -0.730400 | 0.014042 | 1.942234 | 0.892721 | 1.552146 | -1.055182 | 1.718318 |
1 | -0.194978 | -1.374333 | 0.333061 | 0.606212 | -0.536571 | -0.755143 | -0.222781 | 0.717554 | 0.062236 | 0.746278 |
2 | -0.912129 | -1.722085 | -0.756400 | 0.456704 | -0.782453 | -0.630722 | -0.846685 | 2.628396 | -0.960793 | 0.873283 |
您可以通过设置display.max_colwidth来调整各个列的最大宽度。
datafile = { "filename": ["filename_01", "filename_02"], "path": [ "media/user_name/storage/folder_01/filename_01", "media/user_name/storage/folder_02/filename_02", ], } pd.set_option("display.max_colwidth", 30) pd.DataFrame(datafile) Out[129]: filename path 0 filename_01 media/user_name/storage/fo... 1 filename_02 media/user_name/storage/fo... pd.set_option("display.max_colwidth", 100) pd.DataFrame(datafile) Out[131]: 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列标签是有效的Python变量名,则可以像访问属性一样访问该列:
df = pd.DataFrame({"foo1": np.random.randn(5), "foo2": np.random.randn(5)}) df
foo1 | foo2 | |
---|---|---|
0 | 0.918843 | 0.952254 |
1 | -0.763186 | -0.939310 |
2 | -0.028110 | 0.084321 |
3 | -1.428816 | 0.124293 |
4 | -1.769076 | 0.544357 |
这些列还连接到IPython完成机制,因此它们可以用tab键完成:
df.foo1, df.foo2
(0 0.918843 1 -0.763186 2 -0.028110 3 -1.428816 4 -1.769076 Name: foo1, dtype: float64, 0 0.952254 1 -0.939310 2 0.084321 3 0.124293 4 0.544357 Name: foo2, dtype: float64)