检查Pandas DataFrame单元格是否包含特定字符串

55ooxyrt  于 2023-03-28  发布在  其他
关注(0)|答案(2)|浏览(228)

假设我有下面的Pandas数据框:

a               b
0  NAN  BABA UN EQUITY
1  NAN            2018
2  NAN            2017
3  NAN            2016
4  NAN             NAN
5  NAN   700 HK EQUITY
6  NAN            2018
7  NAN            2017
8  NAN            2016
9  NAN             NAN

对于b列中的每个单元格,我想检查它是否包含字符串EQUITY。如果包含,我想替换a列中的单元格,下一行用前一个字符串,直到一行是NAN,以获得编辑后的DataFrame,如下所示:

a               b
0             NAN  BABA UN EQUITY
1  BABA UN EQUITY            2018
2  BABA UN EQUITY            2017
3  BABA UN EQUITY            2016
4             NAN             NAN
5             NAN   700 HK EQUITY
6   700 HK EQUITY            2018
7   700 HK EQUITY            2017
8   700 HK EQUITY            2016
9             NAN             NAN

我的实际DataFrame比上面的大得多,但格式是相似的。我在弄清楚如何检查单元格是否包含EQUITY时遇到了麻烦。似乎我应该使用str.contains,但我不清楚如何做到这一点。

pqwbnv8z

pqwbnv8z1#

import numpy as np
import pandas as pd

df = pd.DataFrame({'a': ['NAN', 'NAN', 'NAN', 'NAN', 'NAN', 'NAN', 'NAN', 'NAN', 'NAN', 'NAN'],
 'b': ['BABA UN EQUITY', '2018', '2017', '2016', 'NAN', '700 HK EQUITY', '2018', '2017', '2016', 'NAN']})

# Make sure that all NaN values are `np.nan` not `'NAN'` (strings)
df = df.replace('NAN', np.nan)
mask = df['b'].str.contains(r'EQUITY', na=True)
df.loc[mask, 'a'] = df['b']
df['a'] = df['a'].ffill()
df.loc[mask, 'a'] = np.nan

收益率

a               b
0             NaN  BABA UN EQUITY
1  BABA UN EQUITY            2018
2  BABA UN EQUITY            2017
3  BABA UN EQUITY            2016
4             NaN             NaN
5             NaN   700 HK EQUITY
6   700 HK EQUITY            2018
7   700 HK EQUITY            2017
8   700 HK EQUITY            2016
9             NaN             NaN

上面有一个有点棘手的地方是mask是如何定义的。请注意,str.contains返回一个Series,它不仅包含TrueFalse的值,还包含NaN

In [114]: df['b'].str.contains(r'EQUITY')
Out[114]: 
0     True
1    False
2    False
3    False
4      NaN
5     True
6    False
7    False
8    False
9      NaN
Name: b, dtype: object

str.contains(..., na=True)用于使NaN s被视为True

In [116]: df['b'].str.contains(r'EQUITY', na=True)
Out[116]: 
0     True
1    False
2    False
3    False
4     True
5     True
6    False
7    False
8    False
9     True
Name: b, dtype: bool

有了mask之后,想法很简单:将b中的值复制到a中,只要mask为True:

df.loc[mask, 'a'] = df['b']

向前填充a中的NaN值:

df['a'] = df['a'].ffill()

a中的值替换为NaN,只要mask为True:

df.loc[mask, 'a'] = np.nan
zkure5ic

zkure5ic2#

1.列表解析比str.contains

即使它们是向量化的,Pandas字符串方法也没有优化,所以回退到Python循环通常要快得多,即使是大型 Dataframe 。
例如,以下两个是等价的(然而,无论列的长度如何,列表解析都快了大约3倍):

msk1 = df['b'].str.contains(r'EQUITY', na=True)

msk = [s != s or 'EQUITY' in s for s in df['b'].tolist()]

all(msk == msk1)   # True

也就是说,str.contains(可以说)可读性要好得多;此外,这两个版本都执行得非常快,并且不太可能成为代码性能的瓶颈。

2.多字符串使用"|".join

要检查某列的行中是否存在字符串列表中的任何字符串,请使用|分隔符将它们连接起来,并调用str.contains

lst = ['EQUITY', '16', '19', '20']
msk = df['b'].str.contains(r'|'.join(lst), na=True)
3.可以使用where()mask()进行过滤

通过使用布尔掩码msk来屏蔽列b中的某些值,可以达到最终期望的输出。然后使用ffill()传播值;最后,使用mask()删除条件为True的值。

msk = df['b'].str.contains(r'EQUITY', na=True)
df['a'] = df['b'].where(msk).ffill().mask(msk)

相关问题