【问题标题】:How to insert a character in a list, based on the consecutive appearance of two elements from another list? Python如何根据另一个列表中两个元素的连续出现在列表中插入一个字符? Python
【发布时间】:2018-11-02 15:48:40
【问题描述】:

我有一个包含很多字符串的 DataFrame 和一个根据条件在字符串中插入字符的函数。问题是我的代码以某种方式错误地看到了输入字符串s

列表s 由两个列表中的元素组成:(1) 成员列表 (2) 非成员列表。我的目标是在任何“成员”后面跟着任何两个“非成员”时将数字“1”插入ss 最多应添加一个“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

【问题讨论】:

  • 你的想法中的问题是row[i], row[i+1], ... 的行为不像你期望的那样,尝试print 他们你会看到你没有访问下一行,而是更多你的字符串的字符
  • 是的,谢谢,我确实注意到了。但无法弄清楚如何在列表中的项目之间插入“1”,而不是在列表中的项目内。

标签: python-3.x list pandas


【解决方案1】:

您可以使用 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 并按照您的方式添加行的方式。我正在用concat 写一个答案,但主要的想法是mask 干得好:)
  • 之所以使用“行”是因为实际上s 是一个包含许多列表s 的DataFrame,DataFrame 中的每一行都包含一个列表。那么,是否可以将结果作为一个列表获得,而不是将列表拆分为行?这样结果就变成了这样:['AA', '1', 'EEEE', 'GGG', 'FF']?
  • @twhale 我认为这个答案以您提出的方式回答了问题,您的评论表明实际上,您的 df 是构建的,例如 df = pd.DataFrame({'string':[s]}) 列“字符串”的每一行都是一个列表,那么这是一个不同的问题,对吗?
  • 是的,你是对的。我现在意识到我以错误的方式提出了这个问题!道歉。
  • 那我再问一个新问题。
【解决方案2】:

@ALollz 代码看起来更干净,因为他们使用掩码和 isin,但是是的,转换绝对是这个想法。

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】:

    我喜欢 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']
    

    【讨论】:

      猜你喜欢
      • 2019-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      • 1970-01-01
      • 2015-03-31
      • 1970-01-01
      相关资源
      最近更新 更多