|
36 | 36 | _shared_docs = dict()
|
37 | 37 |
|
38 | 38 |
|
39 |
| -def str_cat_core(array, sep): |
| 39 | +def interleave_sep(all_cols, sep): |
40 | 40 | '''
|
41 | 41 | Auxiliary function for :meth:`str.cat`
|
42 | 42 |
|
43 | 43 | Parameters
|
44 | 44 | ----------
|
45 |
| - array : ndarray |
46 |
| - Array containing the vectors to be concatenated. These vectors must be |
47 |
| - of object type and may not contain any nulls! |
| 45 | + all_cols : list of numpy arrays |
| 46 | + List of arrays to be concatenated with sep |
48 | 47 | sep : string
|
49 | 48 | The separator string for concatenating the columns
|
50 | 49 |
|
51 | 50 | Returns
|
52 | 51 | -------
|
53 |
| - concatenated |
54 |
| - the vector of concatenated results |
| 52 | + list |
| 53 | + The list of arrays interleaved with sep; to be fed to np.sum |
55 | 54 | '''
|
56 | 55 | if sep == '':
|
57 |
| - return array.sum(axis=1) |
58 |
| - else: |
59 |
| - res = array[:, 0] |
60 |
| - for i in range(1, array.shape[1]): |
61 |
| - res += sep + array[:, i] |
62 |
| - return res |
| 56 | + # no need to add empty strings |
| 57 | + return all_cols |
| 58 | + result = [sep] * (2 * len(all_cols) - 1) |
| 59 | + result[::2] = all_cols |
| 60 | + return result |
63 | 61 |
|
64 | 62 |
|
65 | 63 | def _na_map(f, arr, na_result=np.nan, dtype=object):
|
@@ -2098,11 +2096,13 @@ def cat(self, others=None, sep=None, na_rep=None, join=None):
|
2098 | 2096 |
|
2099 | 2097 | # concatenate Series/Index with itself if no "others"
|
2100 | 2098 | if others is None:
|
2101 |
| - if na_rep is None: |
2102 |
| - data = data.dropna() |
2103 |
| - else: |
2104 |
| - data = data.fillna(na_rep) |
2105 |
| - return sep.join(data.values) |
| 2099 | + data = data.astype(object).values |
| 2100 | + mask = isna(data) |
| 2101 | + if mask.any(): |
| 2102 | + if na_rep is None: |
| 2103 | + return sep.join(data[~mask]) |
| 2104 | + return sep.join(np.where(mask, na_rep, data)) |
| 2105 | + return sep.join(data) |
2106 | 2106 |
|
2107 | 2107 | try:
|
2108 | 2108 | # turn anything in "others" into lists of Series
|
@@ -2145,18 +2145,27 @@ def cat(self, others=None, sep=None, na_rep=None, join=None):
|
2145 | 2145 | join=(join if join == 'inner' else 'outer'),
|
2146 | 2146 | keys=range(len(others)), copy=False)
|
2147 | 2147 | data, others = data.align(others, join=join)
|
2148 |
| - df = concat([data, others], axis=1, copy=False).astype('object') |
2149 |
| - else: |
2150 |
| - df = concat([data] + others, axis=1, copy=False).astype('object') |
2151 |
| - |
2152 |
| - # calculate in numpy using str_cat_core; result is 1-dim np.ndarray |
2153 |
| - if na_rep is None: |
2154 |
| - mask = df.isna().values.any(axis=1) |
2155 |
| - result = np.full(len(data), fill_value=np.nan, dtype='object') |
2156 |
| - result[~mask] = str_cat_core(df.values[~mask], sep) |
2157 |
| - else: |
2158 |
| - df = df.fillna(na_rep) |
2159 |
| - result = str_cat_core(df.values, sep) |
| 2148 | + others = [others[x] for x in others] # again list of Series |
| 2149 | + |
| 2150 | + all_cols = [x.astype(object).values for x in [data] + others] |
| 2151 | + masks = np.array([isna(x) for x in all_cols]) |
| 2152 | + union_mask = np.logical_or.reduce(masks, axis=0) |
| 2153 | + |
| 2154 | + if na_rep is None and union_mask.any(): |
| 2155 | + result = np.empty(len(data), dtype=object) |
| 2156 | + np.putmask(result, union_mask, np.nan) |
| 2157 | + |
| 2158 | + not_masked = ~union_mask |
| 2159 | + all_cols = interleave_sep([x[not_masked] for x in all_cols], sep) |
| 2160 | + |
| 2161 | + result[not_masked] = np.sum(all_cols, axis=0) |
| 2162 | + elif na_rep is not None and union_mask.any(): |
| 2163 | + # fill NaNs |
| 2164 | + all_cols = [np.where(masks[i], na_rep, all_cols[i]) |
| 2165 | + for i in range(len(all_cols))] |
| 2166 | + result = np.sum(interleave_sep(all_cols, sep), axis=0) |
| 2167 | + else: # no NaNs |
| 2168 | + result = np.sum(interleave_sep(all_cols, sep), axis=0) |
2160 | 2169 |
|
2161 | 2170 | if isinstance(self._orig, Index):
|
2162 | 2171 | result = Index(result, name=self._orig.name)
|
|
0 commit comments