【问题标题】:Removing rows from dataframe whose first letter is in lowercase从数据框中删除第一个字母为小写的行
【发布时间】:2018-11-09 00:41:11
【问题描述】:

我有一个类似的数据框 -

    FileName        PageNo     LineNo   EntityName  
1   17743633 - 1    TM000002    69      Ambuja Cement Limited
2   17743633 - 1    TM000003    14      Vessel Name
3   17743633 - 1    TM000003    12      tyre Chips (Shredded Tyres)
4   17743633 - 1    TM000006    22      ambuja Cement Limited
5   17743633 - 1    TM000006    28      Binani Cement Limited

我必须从 datframe 中删除那些 EntityName 列的第一个字母为小写的行。即我必须保留以大写开头的值。

到现在我已经习惯了方法-

df['EntityName'] = map(lambda x: x[0].isupper(), df['EntityName'])

但它给出的是 NaN 值。

我尝试的另一件事是正则表达式。

df['EntityName'] = df['EntityName'].str.replace('^[a-z]+$','')

但它没有显示任何效果。

另一个是 -

qw = df.EntityName.str[0]
df = df[qw.isupper()]

但它显示错误 -

“系列”对象没有属性“isupper”

有人可以建议我正确的代码 sn-p 或任何提示吗?

【问题讨论】:

  • 我找到了一个解决方案 - df = df[df.EntityName.apply(lambda x: x[0].isupper())]
  • 如果有人有执行时间更短的解决方案,请分享。

标签: python string python-3.x pandas dataframe


【解决方案1】:

首先通过索引选择第一个字母,然后检查isupperislower并通过boolean indexing过滤:

df = df[df['EntityName'].str[0].str.isupper()]
#for working with NaN and None
#df = df[df['EntityName'].str[0].str.isupper().fillna(False)]

或者:

df = df[~df['EntityName'].str[0].str.islower()]
#for working with NaN and None
df = df[~df['EntityName'].str[0].str.islower().fillna(False)]

或将str.contains 与正则表达式一起使用 - ^ 用于匹配字符串的第一个值:

df = df[df['EntityName'].str.contains('^[A-Z]+')]

如果数据中没有NaNs 的解决方案是列表理解:

df = df[[x[0].isupper() for x in df['EntityName']]]

使用空字符串和NaNs 的更通用解决方案是添加if-else

mask = [x[0].isupper() if isinstance(x,str) and len(x)>0 else False for x in df['EntityName']]
df = df[mask]

print (df)
              FileName          ...                       EntityName
1 17743633 -         1          ...            Ambuja Cement Limited
2 17743633 -         1          ...                      Vessel Name
5 17743633 -         1          ...            Binani Cement Limited

【讨论】:

  • 要使NaN 处理对pandas 有用,您可能需要添加.fillna(False)(需要额外付费)。
  • 是的,比如df = df[df['EntityName'].str[0].str.isupper().fillna(False)]
【解决方案2】:

你可以使用:

df[df.EntityName.str[0].str.isupper()]

【讨论】:

    【解决方案3】:

    为了提高性能,请考虑使用简单的列表理解进行索引并访问您的系列的 numpy 数组表示:

    df = df[[i[0].isupper() for i in df['EntityName'].values]]
    

    如果您不希望您的系列中有任何空字符串,则此解决方案将起作用。

    性能基准测试

    from operator import itemgetter, methodcaller
    
    s = pd.Series(['Hello', 'hello', 'test', 'Test'])
    
    def jpp(s):
        return list(map(methodcaller('isupper'), map(itemgetter(0), s.values)))
    
    def jpp2(s):
        return [i[0].isupper() for i in s.values]
    
    def jez(s):
        return s.str[0].str.isupper()
    
    s = pd.concat([s]*100000)
    
    %timeit jpp(s)   # 116 ms per loop
    %timeit jpp2(s)  # 82 ms per loop
    %timeit jez(s)   # 313 ms per loop
    

    【讨论】:

    • 是的,因为没有NaNs :)
    • 我加df = df[[x[0].isupper() for x in df['EntityName']]]回答,比df[[i[0].isupper() for i in df['EntityName'].values]]慢?
    • @jezrael,当然,没问题 :)
    【解决方案4】:

    查看我认为istitle 的数据可以完成您的工作,即

    df[df['EntityName'].str.istitle()]
    
          FileName    PageNo  LineNo             EntityName
    1  17743633 - 1  TM000002      69  Ambuja Cement Limited
    2  17743633 - 1  TM000003      14            Vessel Name
    5  17743633 - 1  TM000006      28  Binani Cement Limited
    

    【讨论】:

      猜你喜欢
      • 2013-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2020-07-01
      • 2019-08-28
      • 2019-08-19
      相关资源
      最近更新 更多