Skip to content

Commit 07af0f7

Browse files
committed
Modernize the fix for pandas-dev#10043
1 parent ec07ea8 commit 07af0f7

File tree

2 files changed

+73
-149
lines changed

2 files changed

+73
-149
lines changed

doc/source/whatsnew/v0.24.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ Other
425425

426426
- :meth: `~pandas.io.formats.style.Styler.background_gradient` now takes a ``text_color_threshold`` parameter to automatically lighten the text color based on the luminance of the background color. This improves readability with dark background colors without the need to limit the background colormap range. (:issue:`21258`)
427427
- Require at least 0.28.2 version of ``cython`` to support read-only memoryviews (:issue:`21688`)
428+
- Utilize cython version to simplify the treatment of read-only memoryviews in take_nd (:issue:`10043`)
428429
-
429430
-
430431
-

pandas/_libs/algos_take_helper.pxi.in

+72-149
Original file line numberDiff line numberDiff line change
@@ -36,87 +36,6 @@ dtypes = [
3636

3737
def get_dispatch(dtypes):
3838

39-
inner_take_1d_template = """
40-
cdef:
41-
Py_ssize_t i, n, idx
42-
%(c_type_out)s fv
43-
44-
n = indexer.shape[0]
45-
46-
fv = fill_value
47-
48-
%(nogil_str)s
49-
%(tab)sfor i from 0 <= i < n:
50-
%(tab)s idx = indexer[i]
51-
%(tab)s if idx == -1:
52-
%(tab)s out[i] = fv
53-
%(tab)s else:
54-
%(tab)s out[i] = %(preval)svalues[idx]%(postval)s
55-
"""
56-
57-
inner_take_2d_axis0_template = """\
58-
cdef:
59-
Py_ssize_t i, j, k, n, idx
60-
%(c_type_out)s fv
61-
62-
n = len(indexer)
63-
k = values.shape[1]
64-
65-
fv = fill_value
66-
67-
IF %(can_copy)s:
68-
cdef:
69-
%(c_type_out)s *v
70-
%(c_type_out)s *o
71-
72-
#GH3130
73-
if (values.strides[1] == out.strides[1] and
74-
values.strides[1] == sizeof(%(c_type_out)s) and
75-
sizeof(%(c_type_out)s) * n >= 256):
76-
77-
for i from 0 <= i < n:
78-
idx = indexer[i]
79-
if idx == -1:
80-
for j from 0 <= j < k:
81-
out[i, j] = fv
82-
else:
83-
v = &values[idx, 0]
84-
o = &out[i, 0]
85-
memmove(o, v, <size_t>(sizeof(%(c_type_out)s) * k))
86-
return
87-
88-
for i from 0 <= i < n:
89-
idx = indexer[i]
90-
if idx == -1:
91-
for j from 0 <= j < k:
92-
out[i, j] = fv
93-
else:
94-
for j from 0 <= j < k:
95-
out[i, j] = %(preval)svalues[idx, j]%(postval)s
96-
"""
97-
98-
inner_take_2d_axis1_template = """\
99-
cdef:
100-
Py_ssize_t i, j, k, n, idx
101-
%(c_type_out)s fv
102-
103-
n = len(values)
104-
k = len(indexer)
105-
106-
if n == 0 or k == 0:
107-
return
108-
109-
fv = fill_value
110-
111-
for i from 0 <= i < n:
112-
for j from 0 <= j < k:
113-
idx = indexer[j]
114-
if idx == -1:
115-
out[i, j] = fv
116-
else:
117-
out[i, j] = %(preval)svalues[i, idx]%(postval)s
118-
"""
119-
12039
for (name, dest, c_type_in, c_type_out, preval, postval,
12140
can_copy, nogil) in dtypes:
12241
if nogil:
@@ -126,108 +45,112 @@ def get_dispatch(dtypes):
12645
nogil_str = ''
12746
tab = ''
12847

129-
args = dict(name=name, dest=dest, c_type_in=c_type_in,
130-
c_type_out=c_type_out, preval=preval, postval=postval,
131-
can_copy=can_copy, nogil_str=nogil_str, tab=tab)
132-
133-
inner_take_1d = inner_take_1d_template % args
134-
inner_take_2d_axis0 = inner_take_2d_axis0_template % args
135-
inner_take_2d_axis1 = inner_take_2d_axis1_template % args
136-
13748
yield (name, dest, c_type_in, c_type_out, preval, postval, can_copy,
138-
inner_take_1d, inner_take_2d_axis0, inner_take_2d_axis1)
49+
nogil_str, tab)
13950

14051
}}
14152

14253

14354
{{for name, dest, c_type_in, c_type_out, preval, postval, can_copy,
144-
inner_take_1d, inner_take_2d_axis0, inner_take_2d_axis1
55+
nogil_str, tab
14556
in get_dispatch(dtypes)}}
14657

14758

14859
@cython.wraparound(False)
14960
@cython.boundscheck(False)
150-
cdef inline take_1d_{{name}}_{{dest}}_memview({{c_type_in}}[:] values,
151-
int64_t[:] indexer,
152-
{{c_type_out}}[:] out,
153-
fill_value=np.nan):
154-
155-
156-
{{inner_take_1d}}
157-
158-
159-
@cython.wraparound(False)
160-
@cython.boundscheck(False)
161-
def take_1d_{{name}}_{{dest}}(ndarray[{{c_type_in}}, ndim=1] values,
162-
int64_t[:] indexer,
61+
def take_1d_{{name}}_{{dest}}({{if c_type_in != 'object'}}const{{endif}} {{c_type_in}}[:] values,
62+
const int64_t[:] indexer,
16363
{{c_type_out}}[:] out,
16464
fill_value=np.nan):
65+
cdef:
66+
Py_ssize_t i, n, idx
67+
{{c_type_out}} fv
16568

166-
if values.flags.writeable:
167-
# We can call the memoryview version of the code
168-
take_1d_{{name}}_{{dest}}_memview(values, indexer, out,
169-
fill_value=fill_value)
170-
return
171-
172-
# We cannot use the memoryview version on readonly-buffers due to
173-
# a limitation of Cython's typed memoryviews. Instead we can use
174-
# the slightly slower Cython ndarray type directly.
175-
{{inner_take_1d}}
69+
n = indexer.shape[0]
17670

71+
fv = fill_value
17772

178-
@cython.wraparound(False)
179-
@cython.boundscheck(False)
180-
cdef inline take_2d_axis0_{{name}}_{{dest}}_memview({{c_type_in}}[:, :] values,
181-
int64_t[:] indexer,
182-
{{c_type_out}}[:, :] out,
183-
fill_value=np.nan):
184-
{{inner_take_2d_axis0}}
73+
{{nogil_str}}
74+
{{tab}}for i from 0 <= i < n:
75+
{{tab}} idx = indexer[i]
76+
{{tab}} if idx == -1:
77+
{{tab}} out[i] = fv
78+
{{tab}} else:
79+
{{tab}} out[i] = {{preval}}values[idx]{{postval}}
18580

18681

18782
@cython.wraparound(False)
18883
@cython.boundscheck(False)
189-
def take_2d_axis0_{{name}}_{{dest}}(ndarray[{{c_type_in}}, ndim=2] values,
190-
ndarray[int64_t] indexer,
84+
def take_2d_axis0_{{name}}_{{dest}}({{if c_type_in != 'object'}}const{{endif}} {{c_type_in}}[:, :] values,
85+
const int64_t[:] indexer,
19186
{{c_type_out}}[:, :] out,
19287
fill_value=np.nan):
193-
if values.flags.writeable:
194-
# We can call the memoryview version of the code
195-
take_2d_axis0_{{name}}_{{dest}}_memview(values, indexer, out,
196-
fill_value=fill_value)
197-
return
88+
cdef:
89+
Py_ssize_t i, j, k, n, idx
90+
{{c_type_out}} fv
19891

199-
# We cannot use the memoryview version on readonly-buffers due to
200-
# a limitation of Cython's typed memoryviews. Instead we can use
201-
# the slightly slower Cython ndarray type directly.
202-
{{inner_take_2d_axis0}}
92+
n = len(indexer)
93+
k = values.shape[1]
20394

95+
fv = fill_value
20496

205-
@cython.wraparound(False)
206-
@cython.boundscheck(False)
207-
cdef inline take_2d_axis1_{{name}}_{{dest}}_memview({{c_type_in}}[:, :] values,
208-
int64_t[:] indexer,
209-
{{c_type_out}}[:, :] out,
210-
fill_value=np.nan):
211-
{{inner_take_2d_axis1}}
97+
{{if can_copy}}
98+
cdef:
99+
{{c_type_out}} *v
100+
{{c_type_out}} *o
101+
102+
#GH3130
103+
if (values.strides[1] == out.strides[1] and
104+
values.strides[1] == sizeof({{c_type_out}}) and
105+
sizeof({{c_type_out}}) * n >= 256):
106+
107+
for i from 0 <= i < n:
108+
idx = indexer[i]
109+
if idx == -1:
110+
for j from 0 <= j < k:
111+
out[i, j] = fv
112+
else:
113+
v = &values[idx, 0]
114+
o = &out[i, 0]
115+
memmove(o, v, <size_t>(sizeof({{c_type_out}}) * k))
116+
return
117+
{{endif}}
118+
119+
for i from 0 <= i < n:
120+
idx = indexer[i]
121+
if idx == -1:
122+
for j from 0 <= j < k:
123+
out[i, j] = fv
124+
else:
125+
for j from 0 <= j < k:
126+
out[i, j] = {{preval}}values[idx, j]{{postval}}
212127

213128

214129
@cython.wraparound(False)
215130
@cython.boundscheck(False)
216-
def take_2d_axis1_{{name}}_{{dest}}(ndarray[{{c_type_in}}, ndim=2] values,
217-
ndarray[int64_t] indexer,
131+
def take_2d_axis1_{{name}}_{{dest}}({{if c_type_in != 'object'}}const{{endif}} {{c_type_in}}[:, :] values,
132+
const int64_t[:] indexer,
218133
{{c_type_out}}[:, :] out,
219134
fill_value=np.nan):
135+
cdef:
136+
Py_ssize_t i, j, k, n, idx
137+
{{c_type_out}} fv
220138

221-
if values.flags.writeable:
222-
# We can call the memoryview version of the code
223-
take_2d_axis1_{{name}}_{{dest}}_memview(values, indexer, out,
224-
fill_value=fill_value)
139+
n = len(values)
140+
k = len(indexer)
141+
142+
if n == 0 or k == 0:
225143
return
226144

227-
# We cannot use the memoryview version on readonly-buffers due to
228-
# a limitation of Cython's typed memoryviews. Instead we can use
229-
# the slightly slower Cython ndarray type directly.
230-
{{inner_take_2d_axis1}}
145+
fv = fill_value
146+
147+
for i from 0 <= i < n:
148+
for j from 0 <= j < k:
149+
idx = indexer[j]
150+
if idx == -1:
151+
out[i, j] = fv
152+
else:
153+
out[i, j] = {{preval}}values[i, idx]{{postval}}
231154

232155

233156
@cython.wraparound(False)

0 commit comments

Comments
 (0)