如果一个是空的,Pandas会把两个结合起来

ykejflvf  于 2023-02-20  发布在  其他
关注(0)|答案(4)|浏览(164)

我有一张table:
| A类|B|C级|
| - ------|- ------|- ------|
| x|1个|不适用|
| Y型|不适用|四个|
| z|第二章|不适用|
| p|不适用|五个|
| t|六个|七|
我想创建一个新的列D,如果其中一列为空(NA),则该列应合并列B和C:
| A类|B|C级|D级|
| - ------|- ------|- ------|- ------|
| x|1个|不适用|1个|
| Y型|不适用|四个|四个|
| z|第二章|不适用|第二章|
| p|不适用|五个|五个|
| t|六个|七|误差|
如果两列都包含一个值,则应在单元格内返回文本“error”。

cbeh67ev

cbeh67ev1#

你可以先用两个值都存在的行计算一个掩码,然后用列C的值填充列BNA的值,使用第一步计算的掩码,在需要的地方简单地分配NA的值。

error_mask = df['B'].notna() & df['C'].notna()
df['D'] = df['B'].fillna(df['C'])
df.loc[error_mask, 'D'] = pd.NA
df

   A     B     C     D
0  x     1  <NA>     1
1  y  <NA>     4     4
2  z     2  <NA>     2
3  p     3     5  <NA>

OR
df = df['D'].astype(str)
df.loc[error_mask, 'D'] = 'error'

我建议不要给两个值都存在的字符串error赋值,因为这会使整个D列成为object dtype

lh80um4z

lh80um4z2#

有几种方法可以实现这一点。
使用fillnamask

df['D'] = df['B'].fillna(df['C']).mask(df['B'].notna()&df['C'].notna(), 'error')

或者numpy.select

m1 = df['B'].notna()
m2 = df['C'].notna()
df['D'] = np.select([m1&m2, m1], ['error', df['B']], df['C'])

输出:

A    B    C      D
0  x  1.0  NaN    1.0
1  y  NaN  4.0    4.0
2  z  2.0  NaN    2.0
3  p  NaN  5.0    5.0
4  t  6.0  7.0  error
xesrikrc

xesrikrc3#

除了前面的答案之外,您还可以使用一系列.apply()方法和lambda函数来解决这个问题。
考虑您展示的 Dataframe ,其中np.nan为NA值:

df = pd.DataFrame({
    'B':[1, np.nan, 2, np.nan, 6], 
    'C':[np.nan, 4, np.nan, 5, 7]})

首先从相关系列中生成元素列表:

df['D'] = df.apply(lambda x: list(x), axis=1)

这将为您生成一个pd.Series,其中包含一系列值作为元素,例如第一行为[1.0, nan]。接下来,使用numpy中的np.nan != np.nan删除所有np.nan元素(另请参见此处的答案:How can I remove Nan from list Python/NumPy

df['E'] = df['D'].apply(lambda x: [i for i in x if i == i])

最后,通过基于长度的过滤创建error

df['F'] =  df['E'].apply(lambda x: x[0] if len(x) == 1 else 'error')

生成的 Dataframe 如下所示:

B   C   D   E   F
0   1.0 NaN [1.0, nan]  [1.0]   1.0
1   NaN 4.0 [nan, 4.0]  [4.0]   4.0
2   2.0 NaN [2.0, nan]  [2.0]   2.0
3   NaN 5.0 [nan, 5.0]  [5.0]   5.0
4   6.0 7.0 [6.0, 7.0]  [6.0, 7.0]  error

当然,你可以把所有这些都串成一个不那么冗长,但只有一行字的答案:a = df.apply(lambda x: list(x), axis=1).apply(lambda x: [i for i in x if i == i]).apply(lambda x: x[0] if len(x) == 1 else 'error')

liwlm1x9

liwlm1x94#

看一下函数combine_first

df['C'].combine_first(df['B']).mask(df['B'].notna() & df['C'].notna(), 'error')

输出:

0      1.0
1      4.0
2      2.0
3      5.0
4    error
Name: C, dtype: object

相关问题