python - 使用 while 循环比较和修改系列
问题描述
对于我的数据框的每一行,我需要:
- 从逗号分隔的列表中获取最后一个单词;
- 检查这个词是否已经是系列中其他列表的最后一个词;
- 如果不是:从列表末尾循环以获取第一个匹配此条件的列表。
我以一个包含随机字符列表的系列为例
为了更新“最后一个”列,我试图使用一个包含 while 循环的函数,但我不知道如何完成它,实现此目的的最佳实践是什么?
In[5]:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'List': ['6,f,e,w,m,i,n', '7,m,2,n,3,k,i', 'h,e,a,l,5,v,8', 'c,t,i,v,t,n,1', 'o,q,k,2,p', '6,b,p,n,7,1,k', '3,u,v,q,e,1,z,w', 'm,h,o,b,8,6,n'
]})
In[6]:
df
Out[6]:
List
0 6,f,e,w,m,i,n
1 7,m,2,n,3,k,i
2 h,e,a,l,5,v,8
3 c,t,i,v,t,n,1
4 o,q,k,2,p
5 6,b,p,n,7,1,k
6 3,u,v,q,e,1,z,w
7 m,h,o,b,8,6,n
In[14]:
df['Last'] = df['List'].str.split(',').str[-1]
df['List-length'] = df['List'].str.split(",").apply(len)
df['frequency'] = df.groupby('Last')['Last'].transform('count'
df
Out[14]:
List Last List-length frequency
0 6,f,e,w,m,i,n n 7 2
1 7,m,2,n,3,k,i i 7 1
2 h,e,a,l,5,v,8 8 7 1
3 c,t,i,v,t,n,1 1 7 1
4 o,q,k,2,p p 5 1
5 6,b,p,n,7,1,k k 7 1
6 3,u,v,q,e,1,z,w w 8 1
7 m,h,o,b,8,6,n n 7 2
In[1]:
def avoid_singles(d):
index = -2
remaining_items = d['List-length']
number_of_singles = d.loc[d['frequency'] == 1].size
while number_of_singles >= 1:
d['Last'] = np.where((df['frequency'] == 1) & (d['List-length'] >= abs(index)), d['List'].str.split(",").str[index], d['Last'])
df['frequency'] = df.groupby('Last')['Last'].transform('count')
number_of_singles = d.loc[d['frequency'] == 1].size
index += -1
avoid_singles(df)
和预期的Last
列:
Last
0 n
1 k
2 h
3 n
4 k
5 k
6 3
7 n
解决方案
您可以使用DataFrame.apply
遍历样本,然后计算np.equal.outer
每个样本的最后一个字符的字符;np.argwhere
让我们选择与此条件匹配的第一个字符:
import numpy as np
import pandas as pd
df = pd.DataFrame({'List': ['6,f,e,w,m,i,n', '7,m,2,n,3,k,i', 'h,e,a,l,5,v,8', 'c,t,i,v,t,n,1', 'o,q,k,2,p', '6,b,p,n,7,1,k', '3,u,v,q,e,1,z,w', 'm,h,o,b,8,6,n']})
def get_char(row):
l_reverse = row.l[::-1]
mask = np.equal.outer(l_reverse, tmp.l.str[-1])
mask[:, row.i] = False # Do not match with same row.
mask[-1, 0] = True # Set any element in last row to True so we can fallback to the last character.
return l_reverse[np.argwhere(mask)[0, 0]] # Select the first matching character.
tmp = pd.DataFrame.from_dict(dict(
l=df.List.str.split(','),
i=np.arange(len(df))
))
df['Last'] = tmp.apply(get_char, axis=1)
输出以下内容:
0 6,f,e,w,m,i,n n
1 7,m,2,n,3,k,i k
2 h,e,a,l,5,v,8 h
3 c,t,i,v,t,n,1 n
4 o,q,k,2,p k
5 6,b,p,n,7,1,k 1
6 3,u,v,q,e,1,z,w 1
7 m,h,o,b,8,6,n n
请注意样本 5、6 分别输出1
和1
(与您提供的示例相反),但这是根据您指定的规则匹配条件的第一个字符(k
不是任何其他行中的最后一个字符,而是1
(样本 3) )。
推荐阅读
- azure-active-directory - 支持 SAML 4.0 的 Azure AD 能否与支持 SAML 2.0 的 SP 握手
- php - 如何在 SQL 查询的一个迭代中添加一个空格而不影响我的 PHP 中的另一个
- ios - 应用的 Info.plist 必须包含一个 NSPhotoLibraryUsageDescription 键和一个字符串值,向用户解释应用如何使用这些数据
- swift - UITableView/UICollectionView 委托中的 iOS 13 NSDiffableDataSourceSnapshot
- swift - 如何从 UIDragItem 中检索 UIImage?
- javascript - 屏蔽文本输入以验证 MM/YY jquery-mask-plugin
- twilio - 当用户在 Twilio Studio 中挂断电话时发送 POST 请求
- jupyter-notebook - nbconvert 可以加入多个文件的输出吗?
- python - Pandas - 如果列中的值满足条件,则对前几行求和
- php - 我想通过 Ajax 在 PHP 中获取请求的结果,而不在网页中显示 JSON