tools_pandas APIs

[TOC]

数据初始化

1、readcsv

1
df = pd.read_csv('file_path')

2、

1
2
3
4
5
df = pd.DataFrame(columns=['index', 'v2'])
df['index'] = np.arange(10)
df['v2'] = np.random.randn(10)
# 修改某行的v2列值
df.loc[df.index==1, 'c'] = '9'

3、pd 和np转换

首先导入numpy模块、pandas模块、创建一个DataFrame类型数据df

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
import pandas as pd

df=pd.DataFrame({'A':[1,2,3],'B':[4,5,6],'C':[7,8,9]})

1.使用DataFrame中的values方法
df.values

2.使用DataFrame中的as_matrix()方法
df.as_matrix()

3.使用Numpy中的array方法
np.array(df)
语法 操作 返回结果
df.head(n) 查看 DataFrame 对象的前n行 DataFrame
df.tail(n) 查看 DataFrame 对象的最后n行 DataFrame
df.sample(n) 查看 n 个样本,随机 DataFrame

读取列

以下两种方法都可以代表一列:

1
2
3
4
5
df['name'] # 会返回本列的 Series
df.name
df.Q1
# df.1Q 即使列名叫 1Q 也无法使用
# df.my name 有空格也无法调用,可以处理加上下划线

注意,当列名为一个合法的 python 变量时可以直接作为属性去使用。

读取部分行列

有时我们需要按条件选择部分列、部分行,一般常用的有:

操作 语法 返回结果
选择列 df[col] Series
按索引选择行 df.loc[label] Series
按数字索引选择行 df.iloc[loc] Series
使用切片选择行 df[5:10] DataFrame
用表达式筛选行 df[bool_vec] DataFrame

以上操作称为 Fancy Indexing(花式索引),它来自 Numpy,是指传递一个索引序列,然后一次性得到多个索引元素。Fancy Indexing 和 slicing 不同,它通常将元素拷贝到新的数据对象中。索引中可以有切片 slice,或者省略 ellipsis、新轴 newaxis、布尔数组或者整数数组索引等,可以看做是一个多维切片。

接下来我们将重点介绍一下这些查询的方法。

数据遍历

1. 使用 .iterrows()

iterrows() 方法返回 DataFrame 的索引标签和相应的行数据。这是一个迭代器,它会产生 (index, Series) 对,其中索引是行索引(如果有),Series 是该行的数据。

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd

# 创建示例 DataFrame
data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
df = pd.DataFrame(data)

# 遍历每一行
for index, row in df.iterrows():
print(f"Index: {index}")
print(f"Row data: {row}")
print()

2. 使用 .itertuples()

itertuples() 方法返回一个迭代器,用于迭代 DataFrame 行作为命名元组。这种方式比使用 iterrows() 更快一些,因为不需要创建 Series 对象。

1
2
3
4
5
# 遍历每一行
for row in df.itertuples(index=True, name='Pandas'):
print(f"Index: {row.Index}")
print(f"Data: A={row.A}, B={row.B}")
print()

3. 使用 .apply()

apply() 方法可以应用于整个 DataFrame 或者沿着一个轴应用到每一列或每一行上。这里我们使用 axis=1 来对每一行应用函数。

1
2
3
4
def process_row(row):
print(f"Processing row: {row}")

df.apply(process_row, axis=1)

4. 使用 .loc.iloc

如果你想要更灵活地访问特定行或列的数据,可以使用 .loc.iloc 方法。

1
2
3
4
5
6
7
8
9
10
# 使用 .loc 按照标签索引访问
for index in df.index:
print(f"Index: {index}")
print(f"Row data: {df.loc[index]}")
print()

# 使用 .iloc 按照位置索引访问
for i in range(len(df)):
print(f"Row {i} data: {df.iloc[i]}")
print()

切片 [行/列]

我们可以像列表那样利用切片功能选择部分行的数据,但是不支持索引一条:

1
2
3
4
5
df[:2] # 前两行数据
df[4:10]
df[:] # 所有数据,一般没这么用的
df[:10:2] # 按步长取
s[::-1] # 反转顺序

也可以选择列:

1
2
3
df['name'] # 只要一列,Series
df[['Q1', 'Q2']] # 选择两列
df[['name']] # 选择一列,返回 DataFrame,注意和上例区别

按标签 .loc(行)

df.loc() 的格式为 df.loc[<索引表达式>, <列表达式>],表达式支持以下形式:

单个标签:

1
2
3
# 代表索引,如果是字符需要加引号
df.loc[0] # 选择索引为 0 的行
df.loc[8]

单个列表标签:

1
2
3
4
5
name, value, socre, grade
Eli,9,23,C
Ben,8,89,A
Tom,7,65,B
Toni,6,34,C
1
2
3
4
5
6
df.loc[[0,5,10]] # 指定索引 0,5,10 的行
df.loc[['Eli', 'Ben']] # 如果行索引是 name,提取所有列
df.loc[['Eli', 'Ben'],["name", "grade"]] # 如果行索引是 name, 提取指定列
df.loc[:,["name", "grade"]]
# 真假选择,长度要和索引一样
df.loc[[False, True]*50] # 为真的列显示,隔一个显示一个

带标签的切片,包括起始和停止start:stop, 可以其中只有一个,返回包括它们的数据:

1
2
3
4
df.loc[0:5] # 索引切片, 代表0-5行,包括5
df.loc['2010':'2014'] # 如果索引是时间可以用字符查询
df.loc[:] # 所有
# 本方法支持 Series

关于 loc 的更详细介绍可访问:loc 查询数据行和列

进行切片操作,索引必须经过排序,意味着索引单调递增或者单调递减,以下代码中其中一个为 True,否则会引发 KeyError 错误。

1
2
3
4
5
6
# 索引单调性
(
df.index.is_monotonic_increasing,
df.index.is_monotonic_decreasing
)
# (True, False)

通过上边的规则可以先对索引排序再执行词义上的查询,如:

1
2
3
4
5
6
7
8
# 姓名开头从 Ad 到 Bo 的
df.set_index('name').sort_index().loc['Ad':'Bo']
# 姓名开头从开始到 Bo 的
df.set_index('name').sort_index().loc[:'Bo']
# 团队名称从 C 到 D 的
df.set_index('team').sort_index().loc['C': 'D']
# 姓名开头从 Te 到 X 的
df.sort_values('name').set_index('name').loc['Te': 'X']

列筛选,必须有行元素:

1
2
3
dft.loc[:, ['Q1', 'Q2']] # 所有行,Q1 和 Q2两列
dft.loc[:, ['Q1', 'Q2']] # 所有行,Q1 和 Q2两列
dft.loc[:10, 'Q1':] # 0-10 行,Q1后边的所有列

按位置 .iloc

df.ilocdf.loc 相似,但只能用自然索引(行和列的 0 - n 索引),不能用标签。

1
2
3
4
5
df.iloc[:3]
df.iloc[:]
df.iloc[:, [1, 2]]
df.iloc[2:20:3]
s.iloc[:3]

如果想筛选多个不连续的行列数据(使用 np.r_),可以使用以下方法:

1
2
3
4
5
# 筛选索引0-4&10&5-29每两行取一个&70-74
df.iloc[np.r_[:5, 10, 15:30:2, 70:75]] # 行
df.iloc[:, np.r_[0, 2:6]] # 列,0列和第2-5列
# 也可以使用追加的方式拼接
df.loc[:5].append(df.loc[10]).append(df.loc[15:30:2])

关于 iloc 的更详细介绍可访问:iloc 数字索引位置选择

取具体值 .at

类似于 loc, 但仅取一个具体的值,结构为 at[<索引>,<列名>]:

1
2
3
4
5
6
7
8
9
10
# 注:索引是字符需要加引号
df.at[4, 'Q1'] # 65
df.at['lily', 'Q1'] # 65 假定索引是 name
df.at[0, 'name'] # 'Liver'
df.loc[0].at['name'] # 'Liver'
# 指定列的值对应其他列的值
df.set_index('name').at['Eorge', 'team'] # 'C'
df.set_index('name').team.at['Eorge'] # 'C'
# 指定列的对应索引的值
df.team.at[3] # 'C'

同样 iat 和 iloc 一样,仅支持数字索引:

1
2
df.iat[4, 2] # 65
df.loc[0].iat[1] # 'E'

.get 可以做类似字典的操作,如果无值给返回默认值(例中是0):

1
2
3
4
df.get('name', 0) # 是 name 列
df.get('nameXXX', 0) # 0, 返回默认值
s.get(3, 0) # 93, Series 传索引返回具体值
df.name.get(99, 0) # 'Ben'

表达式筛选

[] 切片里可以使用表达式进行筛选:

1
2
3
4
5
6
7
df[df['Q1'] == 8] # Q1 等于8
df[~(df['Q1'] == 8)] # 不等于8
df[df.name == 'Ben'] # 姓名为Ben
df.loc[df['Q1'] > 90, 'Q1':] # Q1 大于90,显示Q1后边的所有列
df.loc[(df.Q1 > 80) & (df.Q2 < 15)] # and 关系
df.loc[(df.Q1 > 90) | (df.Q2 < 90)] # or 关系
df[df.Q1 > df.Q2]

df.loc 里的索引部分可以使用表达式进行数据筛选。

1
2
3
4
5
6
7
8
9
10
df.loc[df['Q1'] == 8] # 等于8
df.loc[df.Q1 == 8] # 等于8
df.loc[df['Q1'] > 90, 'Q1'] # Q1 大于90,只显示 Q1 Series
df.loc[df['Q1'] > 90, ['Q1']] # Q1 大于90,只显示 Q1 DataFrame
# 其他表达式与切片一致

# 通过列位置筛选列
df.loc[:, lambda df: df.columns.str.len()==4] # 真假组成的序列
df.loc[:, lambda df: [i for i in df.columns if 'Q' in i]] # 列名列表
df.iloc[:3, lambda df: df.columns.str.len()==2] # 真假组成的序列

逻辑判断和函数:

1
2
3
4
5
6
7
8
9
df.eq() # 等于相等 ==
df.ne() # 不等于 !=
df.le() # 小于等于 >=
df.lt() # 小于 <
df.ge() # 大于等于 >=
df.gt() # 大于 >
# 都支持 axis{0 or ‘index’, 1 or ‘columns’}, default ‘columns’
df[df.Q1.ne(89)] # Q1 不等于8
df.loc[df.Q1.gt(90) & df.Q2.lt(90)] # and 关系 Q1>90 Q2<90

其他函数:

1
2
3
# isin
df[df.team.isin(['A','B'])] # 包含 AB 两组的
df[df.isin({'team': ['C', 'D'], 'Q1':[36,93]})] # 复杂查询,其他值为 NaN

函数筛选

函数生成具体的标签值或者同长度对应布尔索引,作用于筛选:

1
2
3
df[lambda df: df['Q1'] == 8] # Q1为8的
df.loc[lambda df: df.Q1 == 8, 'Q1':'Q2'] # Q1为8的, 显示 Q1 Q2
# 选择字段时尽量使用字典法,属性法在条件表达式时一些情况可能有 bug

函数不仅能应用在行位上,也能应用在列位上。

str查询

模糊查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
data[data.列名.str.contains()]
data[data.列名.str.contains('^某某')]
data[data.列名.str.contains('某某')]
data[data.列名.str.contains('某某$')]


data['列名']=data['列名'].apply(str)#把非字符串格式改为字符串格式

#// 多条件查询
data[data.source.str.contains('某某|某某1')]
# 对条件查询结果进行删除
data[-data.source.str.contains('某某|某某1')]

#数据框去重
DataFrame.drop_duplicates(subset=None,keep='first',inplace=False)
#    按某列去重
data.drop_duplicates(subset='列名',keep='first',inplace=False)
#    按多列去重
data.drop_duplicates(subset=['列名','列名1'],keep='first',inplace=False)

df内置方法

where 和 mask

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
s.where(s > 90) # 不符合条件的为 NaN
s.where(s > 90, 0) # 不符合条件的为 0
# np.where, 大于80是真否则是假
np.where(s>80, True, False)
np.where(df.num>=60, '合格', '不合格')

s.mask(s > 90) # 符合条件的为 NaN
s.mask(s > 90, 0) # 符合条件的为 0

# 例:能被整除的显示,不能的显示相反数
m = df.loc[:,'Q1':'Q4'] % 3 == 0
df.loc[:,'Q1':'Q4'].where(m, -df.loc[:,'Q1':'Q4'])

# 行列相同数量,返回一个 array
df.lookup([1,3,4], ['Q1','Q2','Q3']) # array([36, 96, 61])
df.lookup([1], ['Q1']) # array([36])

mask 和 where 还可以通过数据筛选返回布尔序列:

1
2
3
4
5
# 返回布尔序列,符合条件的行为 True
(df.where((df.team=='A') & (df.Q1>60)) == df).Q1

# 返回布尔序列,符合条件的行为 False
(df.mask((df.team=='A') & (df.Q1>60)) == df).Q1

query

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
df.query('Q1 > Q2 > 90') # 直接写类型 sql where 语句
df.query('Q1 + Q2 > 180')
df.query('Q1 == Q2')
df.query('(Q1<50) & (Q2>40) and (Q3>90)')
df.query('Q1 > Q2 > Q3 > Q4')
df.query('team != "C"')
df.query('team in ["A","B"]')
df.query('team not in ("E","A","B")')
df.query('name.str.contains("am")') # 包含 am 字符
# 对于名称中带有空格的列,可以使用反引号引起来
df.query('B == `team name`')

# 支持传入变量,如:大于平均分40分的
a = df.Q1.mean()
df.query('Q1 > @a+40')
df.query('Q1 > `Q2`+@a')

# df.eval() 用法与 df.query 类似
df[df.eval("Q1 > 90 > Q3 > 10")]
df[df.eval("Q1 > `Q2`+@a")]

filter

使用 filter 可以对行名和列名进行筛选。

1
2
3
4
5
6
7
df.filter(items=['Q1', 'Q2']) # 选择两列
df.filter(regex='Q', axis=1) # 列名包含Q的
df.filter(regex='e$', axis=1) # 以 e 结尾的
df.filter(regex='1$', axis=0) # 正则, 索引名包含1的
df.filter(like='2', axis=0) # 索引中有2的
# 索引中2开头列名有Q的
df.filter(regex='^2', axis=0).filter(like='Q', axis=1)

关于 filter 的详细介绍,可以查阅:Pandas filter 筛选标签

索引选择器 pd.IndexSlice

pd.IndexSlice 的使用方法类似于df.loc[] 切片中的方法,常用在多层索引中,以及需要指定应用范围(subset 参数)的函数中,特别是在链式方法中。

1
2
3
4
5
df.loc[pd.IndexSlice[:, ['Q1', 'Q2']]]
# 变量化使用
idx = pd.IndexSlice
df.loc[idx[:, ['Q1', 'Q2']]]
df.loc[idx[:, 'Q1':'Q4'], :] # 多索引

复杂的选择:

1
2
3
4
5
6
7
# 创建复杂条件选择器
selected = df.loc[(df.team=='A') & (df.Q1>90)]
idxs = pd.IndexSlice[selected.index, 'name']
# 应用选择器
df.loc[idxs]
# 选择这部分区域加样式(样式功能见教程后文介绍)
df.style.applymap(style_fun, subset=idxs)

按数据类型

可以只选择或者排除指定类型数据:

1
2
3
4
5
df.select_dtypes(include=['float64']) # 选择 float64 型数据
df.select_dtypes(include='bool')
df.select_dtypes(include=['number']) # 只取数字型
df.select_dtypes(exclude=['int']) # 排除 int 类型
df.select_dtypes(exclude=['datetime64'])

any 和 all

any 方法如果至少有一个值为 True 是便为 True,all 需要所有值为 True 才为 True。它们可以传入 axis 为 1,会按行检测。

1
2
3
4
# Q1 Q2 成绩全为 80 分的
df[(df.loc[:,['Q1','Q2']] > 80).all(1)]
# Q1 Q2 成绩至少有一个 80 分的
df[(df.loc[:,['Q1','Q2']] > 80).any(1)]

理解筛选原理

df[<表达式>] 里边的表达式如果单独拿出来,可以看到:

1
2
3
4
5
6
7
8
9
10
df.Q1.gt(90)
'''
0 False
1 False
2 False
3 True
4 False
...
Name: Q1, Length: 100, dtype: bool
'''

会有一个由真假值组成的数据,筛选后的结果就是为 True 的内容。

mean() / median() / unique() / value_count()

  • mean()

  • median()

  • unique()

  • value_count()

map & apply

1
2
3
4
5
6
7
8
9
10
# Series数据修改,返回当前列的series
review_points_mean = reviews.points.mean()
reviews.points.map(lambda p: p - review_points_mean)

# DataFrame 引用修改,返回完整的DF数据
def remean_points(row):
row.points = row.points - review_points_mean
return row

reviews.apply(remean_points, axis='columns')

案例实操

获取指定值的索引

有时候我们需要知道指定值所在的位置,即一个值在表中的索引,可以使用以一下方法:

1
2
3
4
5
6
7
8
9
# 指定值的的索引对
np.argwhere(df.values == 'Eorge')
# array([[3, 0]])
# 值为 90 的索引对
np.argwhere(df.values == 90)
'''
array([[33, 2],
[64, 5]])
'''

修改某行某列的值

1
2
3
4
5
import pandas as pd
x2 = pd.read_csv("submit.csv")
# 修改id==80000的行,'isDefault'的值
x2.loc[x2.id==800000,'isDefault'] = 1
x2

相关内容