Python/Pandas:元素逐位除法导致NaN的错误?

2 投票
1 回答
3095 浏览
提问于 2025-04-18 09:24

背景和数据的样子:

我有一个叫做 df 的数据框,里面有好几个列。为了这个问题,我只提取了我关心的列,并把它们保存在 x 里:

df 是一个很大的数据框,我是这样提取数据的:

In [29]: x = df[['date', 'amount', 'price']][:25]

为了让你了解 x 的样子,可以看看这个:

In [30]: x
Out[28]:
     date      amount  price
0  2000-11-01       3     57
1  2000-11-01       2     48
2  2000-11-01       1    135
3  2000-11-01       1     24
4  2000-11-01       2    170
5  2000-11-01       1     46
6  2000-11-01       1     28
7  2000-11-01       1     55
8  2000-11-01       1     90
9  2000-11-01       1     20
10 2000-11-01       1    109
11 2000-11-01       1     25
12 2000-11-01       1    129
13 2000-11-01       1     19
14 2000-11-01       1     19
15 2000-11-01       1    168
16 2000-11-01       1     19
17 2000-11-01       1     29
18 2000-11-01       2     48
19 2000-11-01       1     29
20 2000-11-01       1     98
21 2000-11-01       2     58
22 2000-11-01       1     24
23 2000-11-01       2     56
24 2000-11-01       1     86

In [31]: x.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 25 entries, 0 to 24
Data columns (total 3 columns):
date      25 non-null datetime64[ns]
amount    25 non-null int64
price     25 non-null int64
dtypes: datetime64[ns](1), int64(2)

我想要的:

现在我想要新增一列,里面包含每个单品的价格。具体来说:

  • 当数量为 1 时 -> 这列的值和那一行的 price 是一样的
  • 当数量大于 1 时 -> 这列的值是 price/amount,也就是那一行的价格除以数量

我尝试用布尔索引来实现:

In [32]: x['price1'] = x['price'] # make a full copy of the column

In [33]: rows = x['amount'] > 1

In [34]: x['price1'][rows] = x['price1'][rows] / x['amount'][rows] # change rows where amount>1

这在 数据集 x 上是有效的。输出结果如下:

In [54]: x
Out[54]:
         date  amount  price  price1
0  2000-11-01       3     57      19
1  2000-11-01       2     48      24
2  2000-11-01       1    135     135
3  2000-11-01       1     24      24
4  2000-11-01       2    170      85
5  2000-11-01       1     46      46
6  2000-11-01       1     28      28
7  2000-11-01       1     55      55
8  2000-11-01       1     90      90
9  2000-11-01       1     20      20
10 2000-11-01       1    109     109
11 2000-11-01       1     25      25
12 2000-11-01       1    129     129
13 2000-11-01       1     19      19
14 2000-11-01       1     19      19
15 2000-11-01       1    168     168
16 2000-11-01       1     19      19
17 2000-11-01       1     29      29
18 2000-11-01       2     48      24
19 2000-11-01       1     29      29
20 2000-11-01       1     98      98
21 2000-11-01       2     58      29
22 2000-11-01       1     24      24
23 2000-11-01       2     56      28
24 2000-11-01       1     86      86

问题:

当我从 df 中提取更大范围的数据时,使用这段完整的代码:

x = df[['date', 'amount', 'price']][:100]
x['price1'] = x['price']
rows = x['amount'] > 1
x['price1'][rows] = x['price'][rows] / x['amount'][rows]

结果有些除法会得到 NaN:

In [113]: x                         
Out[113]:                           
         date  amount  price  price1
0  2000-11-01       3     57      19 <<
1  2000-11-01       2     48      24 <<
2  2000-11-01       1    135     135
3  2000-11-01       1     24      24
4  2000-11-01       2    170     NaN 
5  2000-11-01       1     46      46
6  2000-11-01       1     28      28
7  2000-11-01       1     55      55
8  2000-11-01       1     90      90
9  2000-11-01       1     20      20
10 2000-11-01       1    109     109
11 2000-11-01       1     25      25
12 2000-11-01       1    129     129
13 2000-11-01       1     19      19
14 2000-11-01       1     19      19
15 2000-11-01       1    168     168
16 2000-11-01       1     19      19
17 2000-11-01       1     29      29
18 2000-11-01       2     48     NaN
19 2000-11-01       1     29      29
20 2000-11-01       1     98      98
21 2000-11-01       2     58      85 <<
22 2000-11-01       1     24      24
23 2000-11-01       2     56     NaN
24 2000-11-01       1     86      86
25 2000-11-01       1    145     145
26 2000-11-01       1     29      29
27 2000-11-01      12    434     NaN
28 2000-11-01       1     46      46
29 2000-11-01       1     52      52
..        ...     ...    ...     ...
70 2000-11-01       1     38      38
71 2000-11-01       1     80      80
72 2000-11-01       1     79      79
73 2000-11-01       2    140      24 <<
74 2000-11-01       1     38      38
75 2000-11-01       1     40      40
76 2000-11-01       3     78     NaN
77 2000-11-01       2    104     NaN
78 2000-11-01       2    130      29 <<
79 2000-11-01       1     96      96
80 2000-11-01       1     42      42
81 2000-11-01       1    109     109
82 2000-11-01       1     89      89
83 2000-11-01       1     26      26
84 2000-11-01       1     49      49
85 2000-11-01       1    135     135
86 2000-11-01       1     38      38
87 2000-11-01       1     29      29
88 2000-11-01       2     46     NaN
89 2000-11-01       1     89      89
90 2000-11-01       1     25      25
91 2000-11-01       2    118      28 <<
92 2000-11-01       1     85      85
93 2000-11-01       1     52      52
94 2000-11-01       1     42      42
95 2000-11-01       2     84     NaN
96 2000-11-01       1     18      18
97 2000-11-01       1     28      28
98 2000-11-01       1     85      85
99 2000-11-01       1    102     102                                        
[100 rows x 4 columns]              

奇怪的是,有些除法是有效的(用 << 标记的)。你们觉得可能出什么问题了?谢谢!

对可能“错误”的进一步了解?

我多尝试了一下,当我在除法之前把新列 price1 转换成 float64 类型时,似乎就能正常工作。对我来说,这看起来像是一个错误。我甚至可以在除法后把它转换回 int64,结果也没问题。我不知道为什么在小范围(比如我 do x = df[...][:25])时能正确工作!?

x = df[['date', 'amount', 'price']][:100]
x['price1'] = x['price'].astype(float64)
rows = x['amount'] > 1
x['price1'][rows] = (x['price1'][rows] / x['amount'][rows]).astype(int64)
x

结果是:

In [146]: x = df[['date', 'amount', 'price']][:100]

In [147]: x['price1'] = x['price'].astype(float64)

In [148]: rows = x['amount'] > 1

In [149]: x['price1'][rows] = (x['price1'][rows] / x['amount'][rows]).astype(int64)

In [150]: x
Out[150]:
         date  amount  price  price1
0  2000-11-01       3     57      19
1  2000-11-01       2     48      24
2  2000-11-01       1    135     135
3  2000-11-01       1     24      24
4  2000-11-01       2    170      85
5  2000-11-01       1     46      46
6  2000-11-01       1     28      28
7  2000-11-01       1     55      55
8  2000-11-01       1     90      90
9  2000-11-01       1     20      20
10 2000-11-01       1    109     109
11 2000-11-01       1     25      25
12 2000-11-01       1    129     129
13 2000-11-01       1     19      19
14 2000-11-01       1     19      19
15 2000-11-01       1    168     168
16 2000-11-01       1     19      19
17 2000-11-01       1     29      29
18 2000-11-01       2     48      24
19 2000-11-01       1     29      29
20 2000-11-01       1     98      98
21 2000-11-01       2     58      29
22 2000-11-01       1     24      24
23 2000-11-01       2     56      28
24 2000-11-01       1     86      86
25 2000-11-01       1    145     145
26 2000-11-01       1     29      29
27 2000-11-01      12    434      36
28 2000-11-01       1     46      46
29 2000-11-01       1     52      52
..        ...     ...    ...     ...
70 2000-11-01       1     38      38
71 2000-11-01       1     80      80
72 2000-11-01       1     79      79
73 2000-11-01       2    140      70
74 2000-11-01       1     38      38
75 2000-11-01       1     40      40
76 2000-11-01       3     78      26
77 2000-11-01       2    104      52
78 2000-11-01       2    130      65
79 2000-11-01       1     96      96
80 2000-11-01       1     42      42
81 2000-11-01       1    109     109
82 2000-11-01       1     89      89
83 2000-11-01       1     26      26
84 2000-11-01       1     49      49
85 2000-11-01       1    135     135
86 2000-11-01       1     38      38
87 2000-11-01       1     29      29
88 2000-11-01       2     46      23
89 2000-11-01       1     89      89
90 2000-11-01       1     25      25
91 2000-11-01       2    118      59
92 2000-11-01       1     85      85
93 2000-11-01       1     52      52
94 2000-11-01       1     42      42
95 2000-11-01       2     84      42
96 2000-11-01       1     18      18
97 2000-11-01       1     28      28
98 2000-11-01       1     85      85
99 2000-11-01       1    102     102

[100 rows x 4 columns]

1 个回答

2

你正在做链式赋值,这种做法其实不太好,因为有时候它可能不管用,这就是你现在遇到的问题。你可以查看这个链接了解更多信息:http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

而且,如果可以的话,你应该总是使用 .loc。如果我们比较一下使用掩码和不使用掩码的性能,你会发现对于一个有25000行的数据表,基于你的样本数据,不使用掩码的速度更快:

In [17]:

%%timeit
x = df[['date', 'amount', 'price']][:100]
x['price1'] = x['price']
rows = x['amount'] > 1
x.loc[rows,'price1']= x['price'] / x['amount']
100 loops, best of 3: 2.54 ms per loop

In [19]:   
%timeit x.loc[rows,'price1']= x['price'] / x['amount']
1000 loops, best of 3: 950 µs per loop

这是你原来的代码:

In [23]:

%%timeit
x = df[['date', 'amount', 'price']][:100]
x['price1'] = x['price'].astype(float64)
rows = x['amount'] > 1
x['price1'][rows] = (x['price1'][rows] / x['amount'][rows]).astype(int64)
100 loops, best of 3: 2.48 ms per loop

所以你会发现,对整个数据表进行操作的速度比先选择前100行,再进行掩码处理再除法要快。

撰写回答