首页 > 解决方案 > 使用 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

标签: pythonpandasnumpy

解决方案


您可以使用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 分别输出11(与您提供的示例相反),但这是根据您指定的规则匹配条件的第一个字符(k不是任何其他行中的最后一个字符,而是1(样本 3) )。


推荐阅读