отсортировать один неполный кадр данных на основе полного кадра данных - PullRequest
0 голосов
/ 01 марта 2019

У меня есть два кадра данных для задачи классификации.df_x (данные, незаконченная головоломка, с нулями в незаполненных позициях) и df_y (метки, законченная головоломка).

Фреймы данных имеют несколько сотен тысяч строк, поэтому эффективность важна.

Проблема в том, что у меня нет гарантий, что i-й индекс df_x соответствует i-му индексу df_y.Я хотел бы исправить кадры данных так, чтобы их индексы совпадали.

У меня есть эта очень неэффективная реализация, однако я не могу позволить себе сохранить ее.

x2y = [].
no_label = []
for i in df_x.index:
    a = df_x[i:i+1] #receives one line of df_x at a time.
    a = a.loc[:, (a != 0).any(axis=0)] #excludes the zeros (unfilled parts of the puzzle)
    match = True 
    for j in df_y.index: #loops over all lines of df_y
        for a_i in a:
            if (a[0:1][a_i].item() != df_y[j:j+1][a_i].item()):
                match = False #if one element is not present in the final solution, than it goes to the next line in df_y
                break
        if match:
            x2y.append((i,j)) 
            df_y[i:i+1] = df_y[j:j+1] #replace label at the position of interest
            break
    if not match:
        no_label.append(i) #unsolved puzzles with no label

так выглядят кадры данных:

df_x.head()
Out[58]: 
    0    1    2      3    4      5   ...   75   76     77     78   79     80
0  0.0  0.0  0.0    0.0  0.0  168.0  ...  0.0  0.0  886.0    0.0  0.0  973.0
1  0.0  0.0  0.0    0.0  0.0  168.0  ...  0.0  0.0  886.0  899.0  0.0  973.0
2  0.0  0.0  0.0    0.0  0.0  168.0  ...  0.0  0.0  886.0  899.0  0.0  973.0
3  0.0  0.0  0.0    0.0  0.0  168.0  ...  0.0  0.0  886.0  899.0  0.0  973.0
4  0.0  0.0  0.0  149.0  0.0  168.0  ...  0.0  0.0  886.0  899.0  0.0  973.0

[5 rows x 81 columns]

df_y.head()
Out[59]: 
      0      1      2      3      4   ...     76     77     78     79     80
0  112.0  126.0  137.0  149.0  154.0  ...  956.0  961.0  973.0  982.0  997.0
1  112.0  126.0  137.0  149.0  154.0  ...  956.0  961.0  973.0  982.0  997.0
2  112.0  126.0  137.0  149.0  154.0  ...  956.0  961.0  973.0  982.0  997.0
3  112.0  126.0  137.0  149.0  154.0  ...  956.0  961.0  973.0  982.0  997.0
4  112.0  126.0  137.0  149.0  154.0  ...  956.0  961.0  973.0  982.0  997.0

[5 rows x 81 columns]

Я начинаю с панд, поэтому, пожалуйста, будьте осторожны!

EDIT В одном из комментариев был задан пример того, как должны выглядеть соответствующие кадры данных.Итак, следующий пример сделан вручную:

df_x.head()
Out[59]: 
      0      1      2      3      4   ...     76     77     78     79     80
0    0.0  126.0    0.0  149.0    0.0  ...    0.0    0.0    0.0    0.0  997.0
1  111.0    0.0    0.0    0.0  152.0  ...  953.0    0.0    0.0  984.0    0.0
2  112.0    0.0  137.0    0.0    0.0  ...    0.0  961.0    0.0    0.0  997.0
3    0.0  121.0    0.0    0.0    0.0  ...    0.0  962.0  973.0  984.0    0.0
4    0.0    0.0  133.0  144.0  155.0  ...  956.0    0.0  978.0    0.0    0.0

df_y.head()
Out[59]: 
      0      1      2      3      4   ...     76     77     78     79     80
0  112.0  126.0  137.0  149.0  154.0  ...  956.0  961.0  973.0  982.0  997.0
1  111.0  123.0  139.0  147.0  152.0  ...  955.0  968.0  973.0  984.0  991.0
2  112.0  126.0  137.0  149.0  154.0  ...  956.0  961.0  973.0  982.0  997.0
3  119.0  121.0  138.0  147.0  156.0  ...  959.0  962.0  973.0  984.0  995.0
4  116.0  127.0  133.0  144.0  155.0  ...  956.0  962.0  978.0  989.0  992.0

1 Ответ

0 голосов
/ 01 марта 2019

Добро пожаловать на pandas!Это довольно сложная проблема, потому что похоже, что вы хотите делать сравнения 1e5 * 1e5, что не будет быстрым, независимо от того, что мы делаем, поэтому давайте попробуем ограничить это настолько, насколько это возможно.Во-первых, сделайте все возможное, чтобы разумно ожидать, что соответствующие индексы будут близки.Во-вторых, вот код, который немного упростит ваше сопоставление.

Для двух серий x_row и y_row:

> x_row = pd.Series([1, 2, 0, 4])
> y_row = pd.Series([1, 2, 3, 4])
> ((x_row == y_row) | (x_row == 0)).all()
True

Эта последняя строка является побитовой или (|)между двумя проверками: во-первых, если каждое значение соответствует соответствующему значению в другой серии (T, T, F, T) или значение в x_row равно нулю (F F T F).Битовый или из этих двух логических рядов равен T T T T, поэтому в результате .all() имеет значение True.

Вот пример использования этого в контексте, а также попытки ограничить числоиз сравнений, сделанных только из строки y_df, когда совпадение было найдено.В идеальном случае это будет выполняться столько раз, сколько у вас будет строк.

x2y = []
unmatched_x = []
unmatched_y = df_y.index.tolist()
for x_idx, x_row in df_x:
    match = False
    for y_idx in unmatched_y:
        if ((x_row == df_y.loc[y_idx]) | (x_row == 0)).all():
            match = True
            break
    if match:
        unmatched_y.remove(y_idx)
        x2y.append(x_idx, y_idx)
    else:
        unmatched_x.append(x_idx)

Если вы считаете, что большинство из них совпадают, вы можете отсортировать те, которые выполняютrunning

matches = ((df_x == df_y) | (df_x == 0)).all(axis=1)

Это делает то же самое, но сразу для всего фрейма данных.Он вернет последовательность логических значений, соответствующую тому, соответствует ли каждая строка df_x соответствующей строке df_y.Затем вы можете сортировать те, которые не соответствуют.
df_x[matches] будут только строки, которые соответствуют, или df_x[~matches] будут те, которые не соответствуют.

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