Pandas 过滤和创建新列

3

I have a Pandas df:

import pandas as pd
import numpy as np
df = pd.DataFrame(['Air type:1', 'Space kind:2', 'water', np.NaN], columns = ['A'])

      A
0   Air type:1
1   Space kind:2
2   water
3   NaN

我希望将A中具有“:”的条目拆分为两个新列。因此,我尝试将此操作与.loc筛选器结合使用:
df.loc[(df.A.str.contains(':')) & (~df.A.isnull()), ['B', 'C']] = df.A.str.split(':', expand = True)

结果并不是很有前景:
     A            B       C
0   Air type:1   NaN    NaN
1   Space kind:2 NaN    NaN
2   water        NaN    NaN
3   NaN          NaN    NaN

如果我不进行过滤,它就能正常工作:

df[['B', 'C']] = df.A.str.split(':', expand = True)

           A           B        C
0   Air type:1      Air type    1
1   Space kind:2    Space kind  2
2   water             water    None
3   NaN                NaN     NaN

问题在于 `water` 条目被错误地分配给新列,之后我必须手动修复它。为什么 `loc` + 赋值语句不起作用?理想情况下,我希望得到:
           A           B        C
0   Air type:1      Air type    1
1   Space kind:2    Space kind  2
2   water              NaN     NaN
3   NaN                NaN     NaN
3个回答

3

尝试使用 df.where 检查条件:

c  = c = df['A'].str.contains(":")
#c = df['A'].str.count(":").ge(1)
df[['B', 'C']] = df['A'].str.split(":",expand=True).where(c)

print(df)
              A           B    C
0    Air type:1    Air type    1
1  Space kind:2  Space kind    2
2         water         NaN  NaN
3           NaN         NaN  NaN

非常好用,谢谢。你有任何想法为什么“.loc”结构不起作用吗? - User2321
@User2321 在我的pandas版本中,tat loc构造不幸地引发了一个keyerror。KeyError: "None of [Index(['B', 'C'], dtype='object')] are in the [columns]" - anky
2
说实话,我认为它应该按照我想的那样通过索引工作。也许值得建立一个REPL并通过调试器逐步查看后台的情况。 - Umar.H
1
无法重现,因为在我的版本中,loc仅适用于将系列分配给数据系列,而不适用于数据框,不确定后来的版本是否有任何更改。 - anky

3
另一种使用.extract()的版本:

df[["B", "C"]] = df["A"].str.extract(r"([^:]+):(.*)")
print(df)

打印:

              A           B    C
0    Air type:1    Air type    1
1  Space kind:2  Space kind    2
2         water         NaN  NaN
3           NaN         NaN  NaN

1
另一种方法使用.stack().join
df1 = df.join(

  df.loc[df['A'].str.contains(':')==True]\
              .stack()\
              .str.split(':',expand=True).unstack(1).droplevel(1,1)
)

              A           0    1
0    Air type:1    Air type    1
1  Space kind:2  Space kind    2
2         water         NaN  NaN
3           NaN         NaN  NaN

或直接赋值。
df[['B','C']] = df.loc[df['A'].str.contains(':')==True]\
                              .stack()\
                              .str.split(':',expand=True)\
                              .unstack(1).droplevel(1,1)

              A           B    C
0    Air type:1    Air type    1
1  Space kind:2  Space kind    2
2         water         NaN  NaN
3           NaN         NaN  NaN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接