0
点赞
收藏
分享

微信扫一扫

pandas进阶用法

彩虹_bd07 2022-02-25 阅读 74

一篇比较好的pandas指南,适合已经熟悉pandas,并想掌握一些进阶用法的读者,不适合对pandas完全不了解的新人。文章大部分是Stack Overflow常见问题集合。

pandas 官网 原文连接: https://pandas.pydata.org/pandas-docs/stable/user_guide/cookbook.html

我会在原文基础上进行增删改,添加一些注释。

常见用法

if-then

  1. 对一列数据执行 if-then / if-then-else 操作,把计算结果赋值给一列或多列。
   AAA  BBB  CCC
0    4   10  100
1    5   20   50
2    6   30  -30
3    7   40  -50

对其中一列筛选,并操作另一列:

In [3]: df.loc[df.AAA >= 5, 'BBB'] = -1

In [4]: df
Out[4]: 
   AAA  BBB  CCC
0    4   10  100
1    5   -1   50
2    6   -1  -30
3    7   -1  -50

操作两列:

In [5]: df.loc[df.AAA >= 5, ['BBB', 'CCC']] = 555

In [6]: df
Out[6]: 
   AAA  BBB  CCC
0    4   10  100
1    5  555  555
2    6  555  555
3    7  555  555

可以通过相反逻辑的代码来实现else,如下

df.loc[df.AAA < 5, ["BBB", "CCC"]] = 2000

或者使用mask和pandas的where来实现,下述表示在mask中,True的地方转化为-1000

In [9]: df_mask = pd.DataFrame({'AAA': [True] * 4,
   ...:                         'BBB': [False] * 4,
   ...:                         'CCC': [True, False] * 2})
   ...: 

In [10]: df.where(df_mask, -1000)
Out[10]: 
   AAA   BBB   CCC
0    4 -1000  2000
1    5 -1000 -1000
2    6 -1000   555
3    7 -1000 -1000

也可以使用numpyd where()函数实现

In [13]: df['logic'] = np.where(df['AAA'] > 5, 'high', 'low')

In [14]: df
Out[14]: 
   AAA  BBB  CCC logic
0    4   10  100   low
1    5   20   50   low
2    6   30  -30  high
3    7   40  -50  high

Splitting

通过布尔值切分

In [17]: df[df.AAA <= 5]
Out[17]: 
   AAA  BBB  CCC
0    4   10  100
1    5   20   50

In [18]: df[df.AAA > 5]
Out[18]: 
   AAA  BBB  CCC
2    6   30  -30
3    7   40  -50

条件设置

还是原来的数据df:

   AAA  BBB  CCC
0    4   10  100
1    5   20   50
2    6   30  -30
3    7   40  -50
  1. 通过“和”符号、或符号筛选,返回Series:
In [21]: df.loc[(df['BBB'] < 25) & (df['CCC'] >= -40), 'AAA']
#切选bbb列小于25且ccc列大于-40的aaa列值
Out[21]: 
0    4
1    5
Name: AAA, dtype: int64
In [22]: df.loc[(df['BBB'] > 25) | (df['CCC'] >= -40), 'AAA']
#切选bbb列小于25或ccc列大于-40的aaa列值
Out[22]: 
0    4
1    5
2    6
3    7
Name: AAA, dtype: int64
  1. 筛选后赋值原Dataframe
In [23]: df.loc[(df['BBB'] > 25) | (df['CCC'] >= 75), 'AAA'] = 0.1
#切选bbb列小于25或ccc列大于-40的aaa列值,并赋值为0.1
In [24]: df
Out[24]: 
   AAA  BBB  CCC
0  0.1   10  100
1  5.0   20   50
2  0.1   30  -30
3  0.1   40  -50

用 argsort 选择最接近指定值的行

In [27]: aValue = 43.0
In [28]: df.loc[(df.CCC - aValue).abs().argsort()]
Out[28]: 
   AAA  BBB  CCC
1    5   20   50
0    4   10  100
2    6   30  -30
3    7   40  -50

用二进制运算符动态减少条件列表

#原始数据
   AAA  BBB  CCC
0    4   10  100
1    5   20   50
2    6   30  -30
3    7   40  -50

In [31]: Crit1 = df.AAA <= 5.5
In [32]: Crit2 = df.BBB == 10.0
In [33]: Crit3 = df.CCC > -40.0
#方法1:通过直接硬编码
In [34]: AllCrit = Crit1 & Crit2 & Crit3
#方法2:通过动态生成条件列表,适用于非常多的条件
In [35]: import functools
In [36]: CritList = [Crit1, Crit2, Crit3]
In [37]: AllCrit = functools.reduce(lambda x, y: x & y, CritList)
In [38]: df[AllCrit]
Out[38]: 
   AAA  BBB  CCC
0    4   10  100

有关functools.reduce的官方文档

Selection

  1. 行标签与值作为条件
    用逆运算符 (~)提取掩码,获取反向的内容
In [41]: df[(df.AAA <= 6) & (df.index.isin([0, 2, 4]))]
Out[41]: 
   AAA  BBB  CCC
0    4   10  100
2    6   30  -30
In [52]: df[~((df.AAA <= 6) & (df.index.isin([0, 2, 4])))]
Out[52]: 
   AAA  BBB  CCC
1    5   20   50
3    7   40  -50
  1. 标签切片与位置切片
    数据:
	AAA	BBB	CCC
foo	4	10	100
bar	5	20	50
boo	6	30	-30
kar	7	40	-50

三种切片方法:

#法1:使用loc根据标签切片,包含结尾
n [43]: df.loc['bar':'kar']  #或通用写成df["bar":"kar"]
Out[43]: 
     AAA  BBB  CCC
bar    5   20   50
boo    6   30  -30
kar    7   40  -50

# 使用iloc根据位置切片,不包含结尾
In [44]: df.iloc[0:3] #或通用写成df[0:3]
Out[44]: 
     AAA  BBB  CCC
foo    4   10  100
bar    5   20   50
boo    6   30  -30

注意,如果索引由整数组成但不从 0 开始,或不是逐步递增的,会引发歧义,可以通过iloc和loc进行区分。

df2
	AAA	BBB	CCC
1	4	10	100
2	5	20	50
3	6	30	-30
4	7	40	-50
df2.iloc[1:3]  # Position-oriented
Out[48]: 
   AAA  BBB  CCC
2    5   20   50
3    6   30  -30

In [49]: df2.loc[1:3]  # Label-oriented
Out[49]: 
   AAA  BBB  CCC
1    4   10  100
2    5   20   50
3    6   30  -30
  1. 用 applymap 动态生成新列
   AAA  BBB  CCC
0    1    1    2
1    2    1    1
2    1    2    3
3    3    2    1

In [55]: source_cols = df.columns   # Or some subset would work too
In [56]: new_cols = [str(x) + "_cat" for x in source_cols]#生成新列名
In [57]: categories = {1: 'Alpha', 2: 'Beta', 3: 'Charlie'}
In [58]: df[new_cols] = df[source_cols].applymap(categories.get)
In [59]: df
Out[59]: 
   AAA  BBB  CCC  AAA_cat BBB_cat  CCC_cat
0    1    1    2    Alpha   Alpha     Beta
1    2    1    1     Beta   Alpha    Alpha
2    1    2    3    Alpha    Beta  Charlie
3    3    2    1  Charlie    Beta    Alpha

apply、map和applymap 参见这里和这里

  1. 使用groupby时保留其他列
In [61]: df
Out[61]: 
   AAA  BBB
0    1    2
1    1    1
2    1    3
3    2    4
4    2    5
5    2    1
6    3    2
7    3    3
#方法1:用 idxmin() 提取对应索引
In [62]: df.loc[df.groupby("AAA")["BBB"].idxmin()]
Out[62]: 
   AAA  BBB
1    1    1
5    2    1
6    3    2
#方法2:先排序,再提取每组的第一个值
In [63]: df.sort_values(by="BBB").groupby("AAA", as_index=False).first()
Out[63]: 
   AAA  BBB
0    1    1
1    2    1
2    3    2

这里需注意,虽然提取的结果是一样的,但两者索引不同

举报

相关推荐

0 条评论