Python/Pandas:元素逐位除法导致NaN的错误?
背景和数据的样子:
我有一个叫做 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行,再进行掩码处理再除法要快。