代码之家  ›  专栏  ›  技术社区  ›  twhale

如何根据另一个列表中两个元素的连续外观在列表中插入字符?python

  •  0
  • twhale  · 技术社区  · 8 年前

    我有一个包含大量字符串的数据帧和一个函数,该函数根据条件在字符串中插入一个字符。问题是我的代码以某种方式看到了输入字符串 s 错了。

    名单 由两个列表中的元素组成:(1)成员列表(2)非成员列表。我的目标是将数字“1”插入到 s 当任何“成员”后跟任意两个consequentive“非成员”时。最多应将一个“1”添加到

    import pandas as pd
    members = ['AA', 'BBB', 'CC', 'DDDD']
    non_members = ['EEEE', 'FF', 'GGG', 'HHHHH', 'III', 'JJ']
    s = ['AA', 'EEEE', 'GGG', 'FF']
    

    因此,我尝试为s实现的结果是获得以下输出:

    ['AA', '1', 'EEEE', 'GGG', 'FF']
    

    df = pd.DataFrame(s, columns =['string'])
    d = df['string']
    
    def func(row):
        out = ""
        look = 2
        for i in range(len(row)-look):
            out += row[i]
            if (row[i] in members) & \
               (row[i+1] in non_members) & \
               (row[i+2] in non_members):
                out += '1' + row[i+1:]
                break
        return out
    
    e = d.apply(func)
    print(e)
    

    这将产生以下结果:

    0      
    1    EE
    2     G
    3      
    

    但我希望得到的是:

    ['AA','1','EEEE','GGG','FF']
    

    有什么建议可以解决这个问题吗?

    这个问题与这个问题有关: How to add a character to a list if two items from another list appear consecutively? Python

    3 回复  |  直到 8 年前
        1
  •  1
  •   ALollz    8 年前

    您可以使用shift来确定在何处满足该条件。

    mask = ((df['string'].isin(members)) 
             & (df['string'].shift(-1).isin(non_members)) 
             & (df['string'].shift(-2).isin(non_members)))
    

    插入中间行的一种方法可能是这样做。

    import numpy as np
    df.set_index(df.index*2, inplace=True)
    
    indices = mask[mask==True].index.values+1
    
    df_add = pd.DataFrame(data=np.repeat(1, len(indices)), index=indices, columns=['string'])
    
    pd.concat([df, df_add]).sort_index()
      string
    0     AA
    1      1
    2   EEEE
    4    GGG
    6     FF
    
        2
  •  0
  •   kpie    8 年前

    @ALollz代码看起来更干净,因为他们使用了掩码和isin,但是的,shift绝对是个好主意。

    import pandas as pd
    
    import sys 
    
    def fun(row):
        members = ['AA', 'BBB', 'CC', 'DDDD']
        non_members = ['EEEE', 'FF', 'GGG', 'HHHHH', 'III', 'JJ']
        try:
            if (row["string"] in members):
                if(row["next"] in non_members):
                    if(row["nextnext"] in non_members):
                        return(1)
            return(0)
        except:
            e = sys.exc_info()[0]
            print(e)
            print("!")
            return(0)
        return(0)
    
    def insert_row(idx, df, df_insert):
        dfA = df.iloc[:idx, ]
        dfB = df.iloc[idx:, ]
        df = dfA.append(df_insert).append(dfB).reset_index(drop = True)
        return df
    
    def primary(d):
        df = d.copy()
        a = d.shift(-1)
        b = d.shift(-2)
        df['next'] = a
        df['nextnext'] = b
        e = df.apply(fun,axis=1)
        x = 0
        while( x<len(e) and e[x]==0 ):
            x+=1
        if(x!=len(e)):
            d = insert_row(x+1,d,pd.DataFrame(["1"], columns=["string"]))
        return(d)
    
    s = ['AA', 'EEEE', 'GGG', 'FF']
    
    df = pd.DataFrame(s, columns =['string'])
    print(primary(df))
    
        3
  •  0
  •   Mark Teese    8 年前

    我喜欢ALollz的答案,但更喜欢更直观的方法。下面是一个需要两次插入的示例。

    import pandas as pd
    import numpy as np
    members = ['AA', 'BBB', 'CC', 'DDDD']
    non_members = ['EEEE', 'FF', 'GGG', 'HHHHH', 'III', 'JJ']
    s = ['AA', 'EEEE', 'GGG', 'CC', 'III', 'JJ']
    ser = pd.Series(s)
    # view the multiple "frames" from the list in a dataframe
    df = pd.DataFrame([ser, ser, ser.shift(-1), ser.shift(-2)], 
    index=["orig","s", "s+1", "s+2"]).T
    
       orig     s   s+1  s+2
    0    AA    AA  EEEE  GGG
    1  EEEE  EEEE   GGG   CC
    2   GGG   GGG    CC  III
    3    CC    CC   III   JJ
    4   III   III    JJ  NaN
    5    JJ    JJ   NaN  NaN
    

    df["s"] = df["s"].isin(members)
    df["s+1"] = df["s+1"].isin(non_members)
    df["s+2"] = df["s+2"].isin(non_members)
    df["fulfilled"] = df.all(axis=1)
    
       orig      s    s+1    s+2  fulfilled
    0    AA   True   True   True       True
    1  EEEE  False   True  False      False
    2   GGG  False  False   True      False
    3    CC   True   True   True       True
    4   III  False   True  False      False
    5    JJ  False  False  False      False
    

    获取要插入到最终s_out列表中的“1”位置的索引。这只是原始指数加上仅处于“真实”位置的指数

    index = df.loc[df.fulfilled].index
    df.loc[index, "index in s_out"] = index + np.arange(1, len(index) + 1)
    
       orig      s    s+1    s+2  fulfilled  index in s_out
    0    AA   True   True   True       True             1.0
    1  EEEE  False   True  False      False             NaN
    2   GGG  False  False   True      False             NaN
    3    CC   True   True   True       True             5.0
    4   III  False   True  False      False             NaN
    5    JJ  False  False  False      False             NaN
    

    在所需位置将“1”插入s_out列表。

    s_out = s.copy()
    for i in df["index in s_out"].dropna().astype(int):
        s_out.insert(i, "1")
    s_out
    
    ['AA', '1', 'EEEE', 'GGG', 'CC', '1', 'III', 'JJ']