Lo que intento hacer es clasificar a los empleados por los roles que tienen en una organización. Esto se calcula tomando todos los permisos o listas de acceso que tienen para el software empresarial objetivo.

Hay potencialmente 10.000 usuarios y docenas de permisos por usuario.

Editar: cuando hay grandes cantidades de usuarios, la gran mayoría tendrá un conjunto de permisos limitado. Por ejemplo, todos pueden tener Employee solamente. Los casos más complicados son los usuarios avanzados y habrá mucho menos.

Además, no se deje engañar por los nombres de permisos que he dado, como Acct1 / Acct2, solo están destinados a dar una idea del dominio. La solución que estoy buscando debería funcionar conceptualmente incluso con enteros de clave primaria asignados aleatoriamente como los que se ven en muchas tiendas ORM: existe una relación implícita no entre los permisos.

import pprint
pp = pprint.PrettyPrinter(indent=4)

def classify(employees):
    """employees assigned the same set 
    of permissions are grouped together"""
    roles = dict()
    for user, permissions in employees.items():
        permissions = list(permissions)
        permissions.sort()
        key = tuple(permissions)
        members = roles.setdefault(key, set([]))
        members.add(user)
    return roles

everyone = {
    "Jim": set(["Employee","Acct1","Manager"]),
    "Marion": set(["Employee","Acct1","Acct2"]),
    "Omar": set(["Employee","Acct1"]),
    "Kim": set(["Employee","Acct1"]),
    "Tyler": set(["Employee","Acct1"]),
    "Susan": set(["Employee","Marketing","Manager"]),
}

result = classify(everyone)
print("pass1")
pp.pprint(result)

En este punto, el sistema de clasificación devuelve lo siguiente:

{ ('Acct1', 'Acct2', 'Employee'): set(['Marion']), ('Acct1', 'Employee'): set(['Kim', 'Omar', 'Tyler']), ('Acct1', 'Employee', 'Manager'): set(['Jim']), ('Employee', 'Manager', 'Marketing'): set(['Susan'])}

A partir de esto, podemos observar los datos y asignar manualmente algunos nombres significativos a esos roles.

Senior Accountants - Marion
Accounting Managers - Jim
Accountants - Kim, Omar, Tyler
Marketing Manager - Susan

La asignación es manual, pero la intención es que permanezca lo más "pegajosa" posible incluso cuando las personas son contratadas o se van y cuando cambia el permiso.

Hagamos un segundo pase.

Alguien decidió cambiar el nombre de Acct2 a SrAcct. La gente es contratada, Kim se va.

Esto está representado por los siguientes permisos de empleados:

everyone2 = { "Jim": set(["Employee","Acct1","Manager"]), "Marion": set(["Employee","Acct1","SrAcct"]), "Omar": set(["Employee","Acct1"]), "Tyler": set(["Employee","Acct1"]), "Milton": set(["Employee","JuniorAcct"]), "Susan": set(["Employee","Marketing","Manager"]), "Tim": set(["Employee","Marketing"]), }

El resultado esta vez es:

{ ('Acct1', 'Employee'): set(['Omar', 'Tyler']), ('Acct1', 'Employee', 'Manager'): set(['Jim']), ('Acct1', 'Employee', 'SrAcct'): set(['Marion']), ('Employee', 'JuniorAcct'): set(['Milton']), ('Employee', 'Manager', 'Marketing'): set(['Susan']), ('Employee', 'Marketing'): set(['Tim'])}

Idealmente, reconoceríamos que

Senior Accountants - Marion
Accounting Managers - Jim
Accountants - Omar, Tyler
Marketing Manager - Susan
new role - Tim
new role - Milton

Los roles de Tim ahora se llamarán Marketer, mientras que Milton será Junior Accountant.

Lo importante es que la asignación del nombre del rol es lo suficientemente estable como para permitir razonar sobre la población de empleados, incluso cuando las personas son contratadas y se van (lo más frecuente) y a medida que se agregan o cambian los permisos (mucho menos frecuente). Está bien pedirle al usuario final de vez en cuando que asigne nuevos nombres de roles o que decida entre lazos. Pero la mayoría de las veces, debería funcionar sin problemas. Lo que no debería hace adivinar mal y erróneamente etiquetar a un conjunto de usuarios como el nombre de rol incorrecto.

El problema que tengo es que es fácil observar, pero tanto el conjunto de permisos como el conjunto de usuarios que definen un rol pueden cambiar. El tiempo de clasificación es importante, pero el valor de este mecanismo de clasificación aumenta a medida que aumenta el número de usuarios y permisos.

He intentado extraer "el subconjunto de permisos que definen un rol". Por ejemplo, Employee se asigna a todos, por lo que se puede ignorar. Mientras que (Manager, Acct1), (Manager, Marketing) pertenecen exclusivamente a Jim y Susan. El problema es que se encuentra con una explosión combinacional una vez que obtiene el 20-30% de los casos y nunca termina.

Lo que pienso ahora es respaldar y calcular la nueva clasificación de roles de permiso de empleado para cada generación y luego retroceder para obtener un "mejor ajuste" difuso en comparación con la generación anterior. Elija los que sean razonablemente inequívocos y solicite al usuario que decida sobre los vínculos y asigne nuevos nombres de roles según sea necesario.

Por ejemplo, una coincidencia exacta en los permisos y una coincidencia razonable en los empleados significa que 'Omar', 'Tyler' todavía están Accountants en el pase 2. Por otro lado, si Marion se fue y yo tuve "Jane": set(["Employee","Acct1","SrAcct"]), Tendría que pedirle al usuario final que la arbitre e identifique como Senior Accountant.

En Python, cuando inicializa una variable de instancia (por ejemplo, Acct2), debe hacerlo en su función de clase SrAcct, para que la memoria esté reservada correctamente para esta variable por instancia ( <- my error, ver más abajo ). Cuando desee definir variables de nivel de clase, hágalo fuera de una función y sin el prefijo {{X2}}.…

Estoy bastante seguro de que este tipo de lógica ha sido necesaria antes, así que espero recomendaciones para ver algoritmos y estrategias a seguir.

Ah, y estoy buscando enfoques razonablemente independientes que pueda implementar, y razonar, dentro del contexto de una aplicación Python más grande. No para las recomendaciones de aprendizaje automático sobre cómo configurar los gustos de TensorFlow para que lo haga por mí. Sin embargo, si el empujón llegara a empujar, podría llamar a un lote para hacer la correspondencia.

1
JL Peyret 2 ago. 2017 a las 22:17

2 respuestas

Lo que realmente está creando aquí es un único árbol de jerarquía organizacional. Su algoritmo de agrupación ya es capaz de eso. No los está mostrando dentro de una sola jerarquía, pero podrían mostrarse fácilmente de esa manera.

La parte "subjetiva" de su organización es decidir cuándo es apropiado combinar sucursales en un solo rol organizacional, y decidir en qué orden ordenar los permisos al crear las sucursales (es decir, si desea tener una sola sucursal de administrador, con divisiones debajo de eso, o desea tener sucursales de departamento, cada una con una sucursal de administrador).

Desafortunadamente, no hay forma de que una máquina conozca esas preferencias. Tendrá que tomar todas esas decisiones, especialmente si va a requerir una tasa de falsos positivos del 0%.

La forma más fácil en que puedo pensar para proporcionar esta información de preferencia al algoritmo sería darle una lista ordenada de "pesos" de permisos que usará al construir la jerarquía. Para un primer paso, puede ordenarlos por cuántas personas tener ese permiso. Es posible que necesite una "ponderación" más compleja que un solo conjunto de permisos ordenados. Para una ponderación más compleja, necesitaría especificar "reglas" más complejas que verifiquen la membresía (o no membresía) en múltiples conjuntos de permisos

El segundo bit de información probablemente se proporcionaría de forma interactiva. Dada una visualización de todo el organigrama, elegiría qué conjuntos de permisos se combinarían en un único conjunto organizativo. Aquí es donde también asignaría nombres para mostrar para sus roles a cada grupo (s) de conjunto de permisos.

En cuanto a poder responder a los alquileres / incendios, no debería ser un problema siempre que los permisos sean los mismos. En cuanto a agregar y eliminar permisos de los usuarios, tendría que almacenar permisos y agrupaciones anteriores y compararlos con los permisos actuales para que cada usuario solicite a alguien que apruebe el cambio en el conjunto de permisos de roles o para formar una nueva rama con el nuevo permiso

1
Brendan Abel 2 ago. 2017 a las 19:44

Esta será una respuesta regular, disculpas, pero su problema es muy amplio y requiere algo de lógica en lugar de un código específico.

¿Quizás este problema se abordará mejor como "etiquetas"? Quiero decir que una persona podría ser tanto un empleado, un chico de marketing y un gerente, todo al mismo tiempo (y supongo que tendrá permisos de los 3).

Por lo tanto, sugiero un enfoque diferente: en lugar de agrupar cuentas por sus respectivos permisos, y solo luego nombrarlas manualmente, primero clasificar y nombrar los permisos (al menos los más populares y estables entre ellos) y luego asignar a cada empleado a la categoría correcta ( o varios) dando a cada empleado etiquetas que encapsulan múltiples permisos cada una.

Luego, tendrá bastantes usuarios o permisos sin clasificar, pero es de esperar que pueda pedirles a los usuarios que hagan un poco de clasificación por usted (por ejemplo, describan su posición / permisos) y trabajen con su enfoque en un conjunto de problemas mucho más pequeño.

De esa forma, puede estar seguro de que cuando ingresa un nuevo empleado, se le da la etiqueta adecuada al observar sus permisos y decidir dónde encaja. Y cuando un empleado se va, no hay diferencia, porque no afecta individualmente permisos y etiquetas.

1
Ofer Sadan 2 ago. 2017 a las 19:33