алгоритм определения согласованного кодирования между двумя сериями кодов - PullRequest
0 голосов
/ 31 января 2020

У меня проблема, когда я пытаюсь использовать пешеходный переход для сопоставления кода A с кодом B в наборе данных. Например, это могут быть отраслевые коды в 1990 и 1991 годах, где перепись изменила способ кодирования отраслей. Если я смогу создать гармонизированный код, я смогу использовать этот код для отслеживания тех же отраслей (или новых групп отраслей, если необходимо) во времени. Они обеспечивают перекрестный обход, который будет выглядеть следующим образом:

import pandas as pd
import numpy as np

df = pd.DataFrame([
[0,0],
[1,2],
[1,3],
[2,4],
[3,4],
[4,5],
[4,6],
[5,5],
[10,11],
[10,13],
[11,11]
], columns=list('AB'))

df
     A   B
0    0   0
1    1   2
2    1   3
3    2   4
4    3   4
5    4   5
6    4   6
7    5   5
8   10  11
9   10  13
10  11  11

Таким образом, моим желаемым выводом будет новый столбец, который определяет непересекающиеся коды как в A, так и B. Например, рассмотрим желаемые результаты ниже:

     A   B    C
0    0   0  0.0
1    1   2  1.0
2    1   3  1.0
3    2   4  2.0
4    3   4  2.0
5    4   5  3.0
6    4   6  3.0
7    5   5  3.0
8   10  11  4.0
9   10  13  4.0
10  11  11  4.0

Я начал отвечать на проблему, выполнив сначала простую часть. Это (один ко многим) 1:m и (много к одному) m:1 совпадений, которые я могу просто присвоить общему значению.

sizesA = df.groupby('A').size()
sizesB = df.groupby('B').size()
df['sizeA'] = df['A'].map(sizesA)
df['sizeB'] = df['B'].map(sizesB)

df['C'] = np.nan

next_v = 0

# 1:m matching

for a in df[df.sizeA>=1].A.unique():
    if df[df.A==a]['sizeB'].max()==1:
        df['C'] = np.where(df['A']==a, next_v, df['C'])
        next_v += 1

# m:1 matching

for b in df[df.sizeB>1].B.unique():
    if df[df.B==b]['sizeA'].max()==1:
        df['C'] = np.where(df['B']==b, next_v, df['C'])
        next_v += 1

df
     A   B  sizeA  sizeB    C
0    0   0      1      1  0.0
1    1   2      2      1  1.0
2    1   3      2      1  1.0
3    2   4      1      2  2.0
4    3   4      1      2  2.0
5    4   5      2      2  NaN
6    4   6      2      1  NaN
7    5   5      1      2  NaN
8   10  11      2      2  NaN
9   10  13      2      1  NaN
10  11  11      1      2  NaN

Проблема в том, что (много ко многим) m:m Матчи. Кажется, я не могу придумать хороший способ решения этой проблемы, и я думаю, что это сложная вычислительная проблема. Обратите внимание, что я мог бы просто назначить оставшиеся значения над одним кодом, но это упустит тот факт, что я могу разделить их на два разных кода и при этом сохранить согласованность.

Кроме того, дайте мне знать, если у вас есть какие-либо предложения для названия.

Ответы [ 2 ]

0 голосов
/ 31 января 2020

Я действительно нашел решение. Может быть, не так элегантно.

ungrouped = df['A'].unique().tolist()
Anew = pd.Series(index=sorted(df['A'].unique()))
Bnew = pd.Series(index=sorted(df['B'].unique()))

g = 0

Avals = [ungrouped[0]]

while True:
    Bvals = df[df['A'].isin(Avals)].B.unique().tolist()

    Acheck = df[df['B'].isin(Bvals)].A.unique().tolist()

    if set(Acheck) == set(Avals):
        Anew.loc[Avals] = g
        Bnew.loc[Bvals] = g
        g += 1
        ungrouped = [a for a in ungrouped if a not in Avals]
        if len(ungrouped) == 0:
            break
        Avals = [ungrouped[0]]
    else:
        Avals = Acheck

df['C'] = df['A'].map(Anew)
df
     A   B    C
0    0   0  0.0
1    1   2  1.0
2    1   3  1.0
3    2   4  2.0
4    3   4  2.0
5    4   5  3.0
6    4   6  3.0
7    5   5  3.0
8   10  11  4.0
9   10  13  4.0
10  11  11  4.0
0 голосов
/ 31 января 2020

Должен ли C начинаться с 0 или с 1? Я просто вычел 1, чтобы вы могли начать с 0. Вы можете настроить его для своих нужд.

Использование cumcount и cumsum должно облегчить его.

df['C'] = ((df.groupby('A').cumcount()==0) & (df.groupby('B').cumcount()==0)).cumsum()-1

print(df)

print(df)

     A   B  C
0    0   0  0
1    1   2  1
2    1   3  1
3    2   4  2
4    3   4  2
5    4   5  3
6    4   6  3
7    5   5  3
8   10  11  4
9   10  13  4
10  11  11  4

...