Найти разницу между группами двоичных строк на основе индекса - PullRequest
0 голосов
/ 21 января 2020

Я хочу проанализировать некоторые двоичные данные в столбце и показать, где находятся битовые ошибки, и использовать этот результат для заполнения значений нового столбца, показывая эти индексы. Например,

  id     type       bin
0  1    ERROR  01110010
1  1  CORRECT  11110000
2  1    ERROR  11101000
3  1    ERROR  11110001
4  2  CORRECT  00001111
5  2    ERROR  10100011
6  3  CORRECT  01010101

должно быть ...

   id     type       bin        errors
 0  1    ERROR  01110010        [0, 6]
 1  1  CORRECT  11110000           NaN
 2  1    ERROR  11101000        [3, 4]
 3  1    ERROR  11110001           [7]
 4  2  CORRECT  00001111           NaN
 5  2    ERROR  10100011  [0, 2, 4, 5]
 6  3  CORRECT  01010101           NaN

Я могу найти битовые ошибки и выполнить групповую обработку идентификатора, но я не могу вернуть эти значения обратно в ' столбец ошибок выше. Все, что я получаю, это следующее ...

   id     type       bin errors
 0  1    ERROR  01110010    NaN
 1  1  CORRECT  11110000    NaN
 2  1    ERROR  11101000    NaN
 3  1    ERROR  11110001    NaN
 4  2  CORRECT  00001111    NaN
 5  2    ERROR  10100011    NaN
 6  3  CORRECT  01010101    NaN

MWE:

def diff(a, b):
    return [i for i in range(len(a)) if a[i] != b[i]]

def find_errors(x):
    errors = []
    base = x.loc[x.type == 'CORRECT'].bin.values[0]
    crcs =  x.loc[x.type == 'ERROR'].bin.values
    for crc in crcs:
        e = diff(base, crc)
        errors.append(e)
    if not errors:
        return np.NaN
    else:
        print('Find errors: ', end='')
        print(errors)
        return errors

d1 = {'id': ['1', '1', '1', '1', '2', '2', '3',],
      'type': ['ERROR', 'CORRECT', 'ERROR', 'ERROR',
               'CORRECT', 'ERROR',
               'CORRECT'],
      'bin': ['01110010', '11110000', '11101000', '11110001',
              '00001111', '10100011',
              '01010101']}
df1 = pd.DataFrame(data=d1)

print("Before...")
print(df1)
df1['errors'] = df1.groupby(['id']).apply(lambda x: find_errors(x))
print("After...")
print(df1)

d2 = {'id': ['1', '1', '1', '1', '2', '2', '3',],
      'type': ['ERROR', 'CORRECT', 'ERROR', 'ERROR',
               'CORRECT', 'ERROR',
               'CORRECT'],
      'bin': ['01110010', '11110000',, '11101000', '11110001',
              '00001111', '10100011',
              '01010101'],
      'errors': [np.NaN, ['0', '6'], ['3', '4'], ['7'],
                 np.NaN, ['0', '2', '4', '5'],
                 np.NaN]}
df2 = pd.DataFrame(data=d2)
print("Goal...")
print(df2)

1 Ответ

1 голос
/ 21 января 2020

Вот мой подход

Я думаю, вам нужно создать Ser ie ( check_s в моем решении), где для каждого id есть исправьте bin во всех ячейках, чтобы сравнить и получить Errors. Мы можем использовать GroupBy.transform + first. Для этого мы преобразовали в NaN, где ранее произошла ошибка с series.where. Наконец, мы используем Series.explode и apply(list), чтобы иметь возможность сравнивать строки. Мы используем GroupBy.cumcount для получения индексов ошибок и добавляем их в список, только если m равно True ( m проверяет , где серии различаются , то есть ошибки).

check_s = ( df['bin'].where(df['type'].eq('CORRECT'))
                     .groupby(df['id'])
                     .transform('first').apply(list).explode() )

s =df['bin'].apply(list).explode()

m = s.ne(check_s)
df['Errors'] = ( m.groupby(level = 0).cumcount()
                                     .where(m)
                                     .dropna()
                                     .astype(int)
                                     .groupby(level = 0)
                                     .agg(list) )
print(df)

   id     type       bin        Errors
0   1  CORRECT  11110000           NaN
1   1    ERROR  01110010        [0, 6]
2   1    ERROR  11101000        [3, 4]
3   1    ERROR  11110001           [7]
4   2  CORRECT  00001111           NaN
5   2    ERROR  10100011  [0, 2, 4, 5]
6   3  CORRECT  01010101           NaN

ОБНОВЛЕНО

Если существует более одной ячейки, правильной для каждый идентификатор, мы можем использовать это (, но это медленнее, поэтому лучше использовать преобразование, если в этом нет необходимости ):

check_s = ( df['bin'].where(df['type'].eq('CORRECT'))
                     .groupby(df['id'])
                     .apply(lambda x: x.ffill().bfill()).apply(list).explode() )
...