一、重新索引
pandas 对象的一个重要方法是 reindex,使用reindex可以创建一个新对象,并且原对象的值与新索引对齐重新排列。
import pandas as pd
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=["d", "b", "a", "c"])
obj2 = obj.reindex(["a", "b", "c", "d", "e"])
print(obj)
print(obj2)
pandas对象调用 reindex方法,将根据新索引重新排列数据创建新对象,如果新索引与原索引无法对齐,则未对齐的索引引入缺失值。以上代码中,obj调用reindex方法中包含索引e,而原索引不包含e,因此新对象obj2的索引e引入缺失值NaN。
obj输出如下:
d 4.5
b 7.2
a -5.3
c 3.6
dtype: float64
obj2输出如下:
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
在进行数据分析的时候,我们有时候会插入一些填充值。比如,对于像时间序列这样的有序数据,可能想在重新索引时做一些插值或填充值。reindex方法的method 参数允许我们使用 ffill 等方法来执行此操作,该方法正向填充值。
import pandas as pd
obj3 = pd.Series(["blue", "purple", "yellow"], index=[0, 2, 4])
print(obj3)
o = obj3.reindex(np.arange(6), method="ffill")
print(o)
输出:
0 blue
2 purple
4 yellow
dtype: object
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype: object
在DataFrame中使用reindex可以更改 (行) 索引、列或者两者都可以更改。当仅传递一个序列给reindex时,它会重新索引结果中的行:
import numpy as np
import pandas as pd
#用numpy数组构造DataFrame对象
frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
index=["a", "c", "d"],
columns=["Ohio", "Texas", "California"])
print(frame)
#重新索引frame,因为只传入了一个序列["a", "b", "c", "d"],所以重定义frame的行索引
frame2 = frame.reindex(index=["a", "b", "c", "d"])
print(frame2)
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
重新reindex后输出:
Ohio Texas California
a 0.0 1.0 2.0
b NaN NaN NaN
c 3.0 4.0 5.0
d 6.0 7.0 8.0
要改变DataFrame的列索引,可以在reindex中使用columns参数指定新索引序列。如下:
import numpy as np
import pandas as pd
#用numpy数组构造DataFrame对象
frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
index=["a", "c", "d"],
columns=["Ohio", "Texas", "California"])
print(frame)
states = ["Texas", "Utah", "California"]
#在reindex方法中使用columns参数指定修改列索引序列
f = frame.reindex(columns=states)
print(f)
输出:
Texas Utah California
a 1 NaN 2
c 4 NaN 5
d 7 NaN 8
上面代码中,由于“Ohio” 不在states序列中,因此将从结果中删除该列的数据,同事Utah列填充NaN值。重新索引特定轴的另一种方法是将新的轴标签作为位置参数传递,然后使用 axis 参数(关键字)指定要重新索引的轴:
例如将上面的代码改为 f = frame.reindex(states, axis="columns") 将输出同样的结果。
reindex方法的参数列表如下:
我们还可以使用 loc 运算符重新编制索引,许多人更喜欢这种方式进行重新索引。使用loc运算符时仅当 DataFrame 中已存在所有新索引标签时,才有效(而 reindex 将为新标签插入缺失数据NaN)。例如:
f = frame.loc[["a", "d", "c"], ["California", "Texas"]]
输出:
California Texas
a 2 1
d 8 7
c 5 4
二、从Axis(轴)删除整个条目数据(可理解为按行或按列删除)
根据上面的学习,我们发现基于reindex方法和loc方法运算,也可以删除rows或columns。但更多的可以用drop方法来删除,该方法也返回一个新对象,不改变原对象。
import numpy as np
import pandas as pd
obj = pd.Series(np.arange(5.), index=["a", "b", "c", "d", "e"])
print(obj)
#删除obj中索引c指示的行
new_obj = obj.drop("c")
print(new_obj)
输出:
a 0.0
b 1.0
c 2.0
d 3.0
e 4.0
dtype: float64
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
drop方法生成的新对象new_obj中删除了索引c指示的行。
可以在drop方法中传递序列删除多rows,例如:new_obj2 = obj.drop(["d", "c"]) 输出结果
a 0.0
b 1.0
e 4.0
dtype: float64
在DataFrame中,可以从任何一个Axis(轴)中删除索引值,直接代码演示(注意看代码中的注释说明):
import numpy as np
import pandas as pd
#用一个4x4的NumPy数组创建一个DataFrame对象,用index和columns指定行索引和列标签
data = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=["Ohio", "Colorado", "Utah", "New York"],
columns=["one", "two", "three", "four"])
#打印data出来看下
print(data)
#删除指定的行索引的值
data1 = data.drop(index=["Colorado", "Ohio"])
print(data1)
#删除指定的列标签的值
data2 = data.drop(columns=["two"])
print(data2)
#通过指定轴号删除该轴方向的某个标签的值 例如列标签two。这种方式等价于data.drop(columns=['two'])
data3 = data.drop("two", axis=1)
print(data3)
#通过指定轴名称删除该方向指定列标签的值
data4 = data.drop(["two", "four"], axis="columns")
print(data4)
以上代码原对象data输出:
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
data1输出:
one | two | three | four | |
---|---|---|---|---|
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
data2输出:
one | three | four | |
---|---|---|---|
Ohio | 0 | 2 | 3 |
Colorado | 4 | 6 | 7 |
Utah | 8 | 10 | 11 |
New York | 12 | 14 | 15 |
data3输出(于data2相同结果):
one | three | four | |
---|---|---|---|
Ohio | 0 | 2 | 3 |
Colorado | 4 | 6 | 7 |
Utah | 8 | 10 | 11 |
New York | 12 | 14 | 15 |
data4输出:
one | three | |
---|---|---|
Ohio | 0 | 2 |
Colorado | 4 | 6 |
Utah | 8 | 10 |
New York | 12 | 14 |
三、从Series和DataFrame中索引、选择和筛选数据
还是用代码来学习会比较直观。
import numpy as np
import pandas as pd
#用numpy数组创建一个Series对象obj,并指定其索引
obj = pd.Series(np.arange(4.), index=["a", "b", "c", "d"])
#通过索引选择
print(obj["b"])
#通过index序号选择,这种方式一般不推荐使用,在新的版本中,整数键将始终被视为标签
print(obj[1])
#通过index序号片段选择
print(obj[2:4])
#通过index序列选择
print(obj[["b", "a", "d"]])
#通过index序号序列选择,不推荐使用整数
print(obj[[1, 3]])
#通过布尔运算选择,选择运算结果为True的值
print(obj[obj < 2])
以上代码输出:
1.0
1.0
c 2.0
d 3.0
dtype: float64
b 1.0
a 0.0
d 3.0
dtype: float64
b 1.0
d 3.0
dtype: float64
a 0.0
b 1.0
dtype: float64
虽然我们可以上面这种按标签选择数据的方式,但选择索引值的首选方法是使用特殊的 loc 运算符 。例如:
obj.loc[["b", "a", "d"]] 输出:
b 1.0
a 0.0
d 3.0
dtype: float64
推荐首选 loc 的原因是在使用 [] 进行索引时对整数的处理方式不同。如果索引包含整数,则基于 [] 的常规索引会将整数视为标签,因此行为因索引的数据类型而异。还是用代码举例比较直观,如下:
import numpy as np
import pandas as pd
#索引包含整数
obj1 = pd.Series([1, 2, 3], index=[2, 0, 1])
#索引不包含整数
obj2 = pd.Series([1, 2, 3], index=["a", "b", "c"])
print(obj1)
print(obj2)
print(obj1[[0, 1, 2]])
print(obj2[[0, 1, 2]])
以上obj1输出:
2 1
0 2
1 3
obj2输出:
dtype: int64
a 1
b 2
c 3
dtype: int64
obj1[[0, 1, 2]]输出:
0 2
1 3
2 1
dtype: int64
obj2[[0, 1, 2]]输出:
a 1
b 2
c 3
dtype: int64
在上面的obj2对象上如果使用obj2.loc[[0, 1, 2]]将会报错,因为obj2索引不包含整数。
由于 loc 运算符仅使用标签进行索引,因此还有一个 iloc 运算符,该运算符仅使用整数进行索引,无论索引是否包含整数,都可以一致地工作:
obj1.iloc[[0, 1, 2]] 输出:
2 1
0 2
1 3
dtype: int64
obj2.iloc[[0, 1, 2]] 输出:
a 1
b 2
c 3
dtype: int64
注意:我们也可以使用标签进行切片,但它的工作方式与普通的 Python 切片不同,因为终端节点是包容性的(包含切片首尾元素),例如:obj2.loc["b":"c"] 输出:
b 2
c 3
dtype: int64
还可以通过这种方式修改相应部分的值:obj2.loc["b":"c"] = 5 输出obj2:
a 1
b 5
c 5
dtype: int64
下次学习对 DataFrame 索引,对其索引可以检索出单个值、序列、一列或多列值。