Как отсортировать столбец массивов на основе другого столбца массивов в пандах? - PullRequest
0 голосов
/ 10 января 2019

У меня есть такой фрейм данных:

df1= pd.DataFrame({
    'col1': [np.asarray([1,4,3,2]), np.asarray([9,10,7,5]), np.asarray([100,120,10,22])],
    'col2': [np.asarray([0,1,4,5]), np.asarray([100,101,102,103]), np.asarray([10,11,12,13])]
})

df1
                 col1                  col2
0        [1, 4, 3, 2]          [0, 1, 4, 5]
1       [9, 10, 7, 5]  [100, 101, 102, 103]
2  [100, 120, 10, 22]      [10, 11, 12, 13]

Я хочу отсортировать значения массивов в столбце 2 на основе значений массивов в столбце 1.

Вот мое решение:

sort_idx = df1['col1'].apply(np.argsort).values
for rowidxval, (index, row) in enumerate(df1.iterrows()):
    df1['col1'][index] = df1['col1'][index][sort_idx[rowidxval]]
    df1['col2'][index] = df1['col2'][index][sort_idx[rowidxval]]

Существует ли изящный, питонский способ сделать это вместо грубой силы, сортируя данные по кадрам по строкам? Что делать, если я хочу повторно отсортировать более одного столбца на основе значений в столбце 1?

Ответы [ 3 ]

0 голосов
/ 10 января 2019

Старайтесь избегать использования массивов NumPy в серии. Такая структура данных не будет поддерживать векторизованные вычисления. Поскольку в этом случае все ваши массивы имеют одинаковый размер, вы можете легко разбить их на несколько столбцов:

# STEP 1: split NumPy arrays into separate columns
col1 = pd.DataFrame(df1.pop('col1').values.tolist()).add_prefix('col1_')
col2 = pd.DataFrame(df1.pop('col2').values.tolist()).add_prefix('col2_')
df1 = df1.join(pd.concat([col1, col2], axis=1))

# STEP 2: calculate indices for NumPy assignment
x_idx = np.arange(df1.shape[0])[:, None]
y_idx = df1.iloc[:, :4].values.argsort(1)

# STEP 3: assign via iloc
df1.iloc[:, 4:] = df1.iloc[:, 4:].values[x_idx, y_idx]

print(df1)

#    col1_0  col1_1  col1_2  col1_3  col2_0  col2_1  col2_2  col2_3
# 0       1       4       3       2       0       5       4       1
# 1       9      10       7       5     103     102     100     101
# 2     100     120      10      22      12      13      10      11
0 голосов
/ 10 января 2019

Использование для цикла

[[z for _,z in sorted(zip(x,y))] for x, y in zip(df1.col1, df1.col2)]
Out[250]: [[0, 5, 4, 1], [103, 102, 100, 101], [12, 13, 10, 11]]

#df1.col2=[[z for _,z in sorted(zip(x,y))] for x, y in zip(df1.col1, df1.col2)]
0 голосов
/ 10 января 2019

Списки в столбцах никогда не рекомендуются (смешанные dtypes и изменяемые dtypes создают узкие места и снижают производительность в коде), но вы можете сделать это как можно быстрее, используя понимание списка:

df['col2'] = [np.array(y)[np.argsort(x)] for x, y in zip(df.col1, df.col2)]
df

                 col1                  col2
0        [1, 4, 3, 2]          [0, 5, 4, 1]
1       [9, 10, 7, 5]  [103, 102, 100, 101]
2  [100, 120, 10, 22]      [12, 13, 10, 11]

Если они оба являются массивами, решение упрощается:

df['col2'] = [y[x.argsort()] for x, y in zip(df.col1, df.col2)]
df

                 col1                  col2
0        [1, 4, 3, 2]          [0, 5, 4, 1]
1       [9, 10, 7, 5]  [103, 102, 100, 101]
2  [100, 120, 10, 22]      [12, 13, 10, 11]

Для получения дополнительной информации о проблемах, связанных с производительностью, см. Раздел «Смешанные dtypes» в Для циклов с пандами - Когда мне следует позаботиться? .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...