forked from pandas-dev/pandas
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathreshape.pyx
159 lines (132 loc) · 3.51 KB
/
reshape.pyx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import cython
from cython import Py_ssize_t
from numpy cimport (
float32_t,
float64_t,
int8_t,
int16_t,
int32_t,
int64_t,
ndarray,
uint8_t,
uint16_t,
uint32_t,
uint64_t,
)
import numpy as np
cimport numpy as cnp
cnp.import_array()
from pandas._libs.lib cimport c_is_list_like
ctypedef fused reshape_t:
uint8_t
uint16_t
uint32_t
uint64_t
int8_t
int16_t
int32_t
int64_t
float32_t
float64_t
object
@cython.wraparound(False)
@cython.boundscheck(False)
def unstack(reshape_t[:, :] values, const uint8_t[:] mask,
Py_ssize_t stride, Py_ssize_t length, Py_ssize_t width,
reshape_t[:, :] new_values, uint8_t[:, :] new_mask) -> None:
"""
Transform long values to wide new_values.
Parameters
----------
values : typed ndarray
mask : np.ndarray[bool]
stride : int
length : int
width : int
new_values : np.ndarray[bool]
result array
new_mask : np.ndarray[bool]
result mask
"""
cdef:
Py_ssize_t i, j, w, nulls, s, offset
if reshape_t is not object:
# evaluated at compile-time
with nogil:
for i in range(stride):
nulls = 0
for j in range(length):
for w in range(width):
offset = j * width + w
if mask[offset]:
s = i * width + w
new_values[j, s] = values[offset - nulls, i]
new_mask[j, s] = 1
else:
nulls += 1
else:
# object-dtype, identical to above but we cannot use nogil
for i in range(stride):
nulls = 0
for j in range(length):
for w in range(width):
offset = j * width + w
if mask[offset]:
s = i * width + w
new_values[j, s] = values[offset - nulls, i]
new_mask[j, s] = 1
else:
nulls += 1
@cython.wraparound(False)
@cython.boundscheck(False)
def explode(ndarray[object] values):
"""
transform array list-likes to long form
preserve non-list entries
Parameters
----------
values : object ndarray
Returns
-------
ndarray[object]
result
ndarray[int64_t]
counts
"""
cdef:
Py_ssize_t i, j, count, n
object v
ndarray[object] result
ndarray[int64_t] counts
# find the resulting len
n = len(values)
counts = np.zeros(n, dtype='int64')
for i in range(n):
v = values[i]
if c_is_list_like(v, True):
if len(v):
counts[i] += len(v)
else:
# empty list-like, use a nan marker
counts[i] += 1
else:
counts[i] += 1
result = np.empty(counts.sum(), dtype='object')
count = 0
for i in range(n):
v = values[i]
if c_is_list_like(v, True):
if len(v):
v = list(v)
for j in range(len(v)):
result[count] = v[j]
count += 1
else:
# empty list-like, use a nan marker
result[count] = np.nan
count += 1
else:
# replace with the existing scalar
result[count] = v
count += 1
return result, counts