Python 在不覆盖非选定行的情况下,使用loc对数据帧进行选择性操作

Python 在不覆盖非选定行的情况下,使用loc对数据帧进行选择性操作,python,pandas,dataframe,Python,Pandas,Dataframe,我想应用算术运算来选择数据帧的行,选择取决于另一列 我首先尝试定义一个函数,并使用apply来计算值,但是速度太慢了,因为我猜函数逻辑是针对每一行计算的 使用loc应用该操作要快得多,但是当我依次应用该操作时,每次都会用NaN覆盖未选择的行 一个说明性的例子是: new_df = pd.DataFrame( [[1, 0.1], [1, 0.2], [1, 0.3], [2, 0.4], [2, 0.5]], columns=["class", "size"] ) new_df #

我想应用算术运算来选择数据帧的行,选择取决于另一列

我首先尝试定义一个函数,并使用
apply
来计算值,但是速度太慢了,因为我猜函数逻辑是针对每一行计算的

使用
loc
应用该操作要快得多,但是当我依次应用该操作时,每次都会用NaN覆盖未选择的行

一个说明性的例子是:

new_df = pd.DataFrame(
    [[1, 0.1], [1, 0.2], [1, 0.3], [2, 0.4], [2, 0.5]], columns=["class", "size"]
)
new_df
#    class  size
#    1      0.1
#    1      0.2
#    1      0.3
#    2      0.4
#    2      0.5
假设我想将class==2的所有行的大小值平方,并将class==1的所有行的大小值立方

目标数据帧将是

#    class  size oper_size
#    1      0.1  0.001
#    1      0.2  0.008
#    1      0.3  0.027
#    2      0.4  0.16
#    2      0.5  0.25
但是,如果我这样做:

new_df["oper_size"] = new_df["size"].loc[new_df["class"] == 1] ** 3
new_df["oper_size"] = new_df["size"].loc[new_df["class"] == 2] ** 2
然后,生成的数据帧是:

#  class  size  oper_size
#      1   0.1        NaN
#      1   0.2        NaN
#      1   0.3        NaN
#      2   0.4       0.16
#      2   0.5       0.25

非常感谢您的帮助。

您需要使用
loc
选择要替换的行。例如

new_df.loc[new_df["class"] == 1, "oper_size"] = new_df[new_df["class"] == 1, "oper_size"] ** 3
或定义一个可用于两侧的遮罩:

mask_1 = new_df["class"] == 1
new_df.loc[mask_1, "oper_size"] = new_df[mask_1, "oper_size"] ** 3
或者,您也可以使用
numpy.where
区分两种情况:

new_df['oper_size'] = np.where(new_df['class'] == 1, 
                               new_df['size']**3,
                               new_df['size']**2)
new_df

您可以为
的每个值创建字典,以便可能用于新系列,然后仅使用
**
的幂运算:

new_df["oper_size"] = new_df["size"] ** new_df['class'].map({1:3, 2:2})
print (new_df)
   class  size  oper_size
0      1   0.1      0.001
1      1   0.2      0.008
2      1   0.3      0.027
3      2   0.4      0.160
4      2   0.5      0.250
详细信息

print (new_df['class'].map({1:3, 2:2}))
0    3
1    3
2    3
3    2
4    2
Name: class, dtype: int64
如果某些值与上一行不匹配,则可以将所有值替换为某个数字,例如
0
或某列,例如
大小

new_df = pd.DataFrame(
    [[1, 0.1], [1, 0.2], [1, 0.3], [2, 0.4], [3, 0.5]], columns=["class", "size"]
)


new_df["oper_size1"]=(new_df["size"] ** new_df['class'].map({1:3, 2:2})).fillna(0)
new_df["oper_size2"]=(new_df["size"] ** new_df['class'].map({1:3, 2:2})).fillna(new_df["size"])

print (new_df)
   class  size  oper_size1  oper_size2
0      1   0.1       0.001       0.001
1      1   0.2       0.008       0.008
2      1   0.3       0.027       0.027
3      2   0.4       0.160       0.160
4      3   0.5       0.000       0.500

你好,mcsoini,感谢您的回复-非常有帮助。
new_df = pd.DataFrame(
    [[1, 0.1], [1, 0.2], [1, 0.3], [2, 0.4], [3, 0.5]], columns=["class", "size"]
)


new_df["oper_size1"]=(new_df["size"] ** new_df['class'].map({1:3, 2:2})).fillna(0)
new_df["oper_size2"]=(new_df["size"] ** new_df['class'].map({1:3, 2:2})).fillna(new_df["size"])

print (new_df)
   class  size  oper_size1  oper_size2
0      1   0.1       0.001       0.001
1      1   0.2       0.008       0.008
2      1   0.3       0.027       0.027
3      2   0.4       0.160       0.160
4      3   0.5       0.000       0.500