Pandas数据框:如何通过应用函数更新多列?

22

我有一个名为df的数据框,就像这样:

   A   B   C    D
2  1   O   s    h
4  2   P    
7  3   Q
9  4   R   h    m

我有一个函数f,根据B计算行的C和D:

def f(p): #p is the value of column B for a row. 
     return p+'k', p+'n'

如何使用函数f来填充数据框(Dataframe)中第4行和第7行的缺失值?

期望的结果如下所示:

   A   B   C    D
2  1   O   s    h
4  2   P   Pk   Pn
7  3   Q   Qk   Qn
9  4   R   h    m

由于真实函数非常复杂,因此必须使用函数f。此外,该函数仅需要应用于缺少C和D的行。


请您更新问题,附上完整的函数以便复现整个代码。 - Fabio Lamanna
在函数中添加了虚拟逻辑,以便返回2个值。 - John Smith
1
预期输出是什么?抱歉,我真的不太理解你的函数.. - Colonel Beauvel
希望以下内容能够帮助到您。 - Colonel Beauvel
5个回答

19

也许有更优雅的方式,但我会这样做:

df['C'] = df['B'].apply(lambda x: f(x)[0])
df['D'] = df['B'].apply(lambda x: f(x)[1])

将该函数应用于列并获取输出的第一个和第二个值。它返回:

   A  B   C   D
0  1  O  Ok  On
1  2  P  Pk  Pn
2  3  Q  Qk  Qn
3  4  R  Rk  Rn

EDIT:
更简洁地说,感谢这个回答
df[['C','D']] = df['B'].apply(lambda x: pd.Series([f(x)[0],f(x)[1]]))

函数f必须被使用,因为真实函数非常复杂。此外,该函数只需要应用于缺少C和D的行。 - John Smith
只要该函数返回两个参数,它就应该以这种方式工作。 - Fabio Lamanna
感谢 @Fiabetto。我们如何将该函数应用于仅在C和D列中存在缺失值的行? - John Smith
抱歉 @ColonelBeauvel,我在看到你的回答之前就一直在处理这个问题!我已经更新了答案并注明了你的贡献! - Fabio Lamanna
仍然,我们的回答并没有回答这个问题!我编辑了我的回答以解决这个问题。 - Colonel Beauvel
我认为这个 df[['C','D']] = df['B'].apply(lambda x: pd.Series(f(x))) 就足够了,没有必要将列表拆开再重新打包。 - HerrIvan

11

如果你想使用你的函数本身,这里有一个单行代码:

df.update(df.B.apply(lambda x: pd.Series(dict(zip(['C','D'],f(x))))), overwrite=False)

In [350]: df
Out[350]:
   A  B   C   D
2  1  O   s   h
4  2  P  Pk  Pn
7  3  Q  Qk  Qn
9  4  R   h   m

您也可以这样做:

df1 = df.copy()

df[['C','D']] = df.apply(lambda x: pd.Series([x['B'] + 'k', x['B'] + 'n']), axis=1)

df1.update(df, overwrite=False)

这看起来很好,但它没有使用函数f。 - John Smith
1
现在的解决方案使用了您的函数f,而无需重新修改它! - Colonel Beauvel

6

如果表格不是很大,我有一种更简单的方法来完成它。

def f(row): #row is the value of row. 
    if row['C']=='':
        row['C']=row['B']+'k'
    if row['D']=='':
        row['D']=row['B']+'n'
    return row
df=df.apply(f,axis=1)

0

我发现这个超级令人困惑,但最终找到了一种不会让我的大脑受伤的实现方法。抱歉如果它与示例不太匹配...

没有索引的数据框

# function to do the calcs
def f(row):
    my_a = row['a'] # row is a Series, my_a is a scalar string

    if my_a == 'a':  # dummy logic to calc new values based on the row values
        return [1, 2] # return 2 values to update 2 columns
    else:
        return [4, 5]

# simple test frame
input = pd.DataFrame.from_dict({
    'a': ['a', 'd'],
    'b': ['b', 'e'],
    'c': ['c', 'f'],
    'x': [0, 0],
    'y': [0, 0]
})

# apply the function to update the x and y columns with the returned values
input[['x','y']] = input.apply(f, axis=1)

带索引的数据框

如果您的数据框具有索引..在执行应用程序时,您需要更加明确,以确保“类似列表的结果将被转换为列”...

def f(row): # function to do the calcs
    my_a = row['a'] # row is a Series, my_a is a scalar string
    my_index = row.name # you might also want to use the index value in the calcs

    if my_a == 'a': # dummy logic to calc new values based on the row values
        return [1, 2] # return 2 values to update 2 columns
    else:
        return [4, 5]

input = pd.DataFrame.from_dict({
    'an_index': ['indx1', 'indx2'],
    'a': ['a', 'd'],
    'b': ['b', 'e'],
    'c': ['c', 'f'],
    'x': [0, 0],
    'y': [0, 0]
}).set_index(['an_index'])

# apply the function to update the x and y columns with the returned values
input[['x','y']] = input.apply(f, axis=1, result_type='expand')

0

仅通过以下方式就可以

df.C.loc[df.C.isnull()] = df.B.loc[df.C.isnull()] + 'k'

df.D.loc[df.D.isnull()] = df.B.loc[df.D.isnull()] + 'n'

如果你想知道我为什么使用loc,请查看此链接indexing-view-versus-copy


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