Pregunta

Tengo una lista con una gran cantidad de líneas, cada una de las cuales toma la forma sujeto-verbo-objeto, por ejemplo:

Jane likes Fred
Chris dislikes Joe
Nate knows Jill

Para trazar un gráfico de red que exprese las diferentes relaciones entre los nodos en bordes dirigidos codificados por colores, necesitaré reemplazar el verbo con una flecha y colocar un código de color al final de cada línea, por lo tanto, algo simplificado:

Jane -> Fred red;
Chris -> Joe blue;
Nate -> Jill black;

Sólo hay una pequeña cantidad de verbos, por lo que reemplazarlos con una flecha es solo cuestión de unos pocos comandos de búsqueda y reemplazo.Sin embargo, antes de hacer eso, tendré que poner un código de color al final de cada línea que corresponda al verbo de la línea.Me gustaría hacer esto usando Python.

Estos son mis pequeños pasos en programación, así que sea explícito e incluya el código que se lee en el archivo de texto.

¡Gracias por tu ayuda!

¿Fue útil?

Solución

verbs = {"dislikes":"blue", "knows":"black", "likes":"red"}
for s in open("/tmp/infile"):
  s = s.strip()
  for verb in verbs.keys():
    if (s.count(verb) > 0):
      print s.replace(verb,"->")+" "+verbs[verb]+";"
      break

Edit: utilizar más bien "para s en abierto"

Otros consejos

Parece que tendrá que investigar diccionarios y formato de cadenas . En general, si necesita ayuda para la programación, simplemente romper cualquier problema que tenga en trozos muy pequeños y discretos, buscar esos trozos de forma independiente, y entonces usted debería ser capaz de formular todo en una respuesta más amplia. Desbordamiento de pila es un gran recurso para este tipo de búsqueda.

Además, si tiene alguna curiosidades generales sobre Python, buscar o navegar por la documentación oficial de Python . Si usted se encuentra constantemente sin saber por dónde empezar, lea la Guía de aprendizaje de o encontrar una libro para ir a través. Una semana o dos inversiones para obtener un buen conocimiento básico de lo que está haciendo va a pagar una y otra vez a medida que el trabajo completo.

verb_color_map = {
    'likes': 'red',
    'dislikes': 'blue',
    'knows': 'black',
}

with open('infile.txt') as infile: # assuming you've stored your data in 'infile.txt'
    for line in infile:
        # Python uses the name object, so I use object_
        subject, verb, object_ = line.split()
        print "%s -> %s %s;" % (subject, object_, verb_color_map[verb])

Bastante simple; asumiendo las listas de verbos es fijo y pequeño, esto es fácil de hacer con un diccionario y for bucle:

VERBS = {
    "likes": "red"
  , "dislikes": "blue"
  , "knows": "black"
  }

def replace_verb (line):
    for verb, color in VERBS.items():
        if verb in line:
            return "%s %s;" % (
                  line.replace (verb, "->")
                , color
                )
    return line

def main ():
    filename = "my_file.txt"
    with open (filename, "r") as fp:
        for line in fp:
            print replace_verb (line)

# Allow the module to be executed directly on the command line
if __name__ == "__main__":
    main ()

¿Estás seguro de que esto no es un poco homeworky :) Si es así, está bien que confesar. Sin entrar en demasiados detalles, piense en las tareas que estamos tratando de hacer:

Para cada línea:

  1. leerlo
  2. dividirlo en palabras (el espacio en blanco - .split ())
  3. convertir la palabra en un color medio (basado en un mapeo -> CF: dict pitón ()
  4. imprimir la primera palabra, flecha, tercera palabra y el color

Código usando NetworkX (networkx.lanl.gov /)

'''
plot relationships in a social network
'''

import networkx
## make a fake file 'ex.txt' in this directory
## then write fake relationships to it.
example_relationships = file('ex.txt','w') 
print >> example_relationships, '''\
Jane Doe likes Fred
Chris dislikes Joe
Nate knows Jill \
'''
example_relationships.close()

rel_colors = {
    'likes':  'blue',
    'dislikes' : 'black',
    'knows'   : 'green',
}

def split_on_verb(sentence):
    ''' we know the verb is the only lower cased word

    >>> split_on_verb("Jane Doe likes Fred")
    ('Jane Does','Fred','likes')

    '''
    words = sentence.strip().split()  # take off any outside whitespace, then split
                                       # on whitespace
    if not words:
        return None  # if there aren't any words, just return nothing

    verbs = [x for x in words if x.islower()]
    verb = verbs[0]  # we want the '1st' one (python numbers from 0,1,2...)
    verb_index = words.index(verb) # where is the verb?
    subject = ' '.join(words[:verb_index])
    obj =  ' '.join(words[(verb_index+1):])  # 'object' is already used in python
    return (subject, obj, verb)


def graph_from_relationships(fh,color_dict):
    '''
    fh:  a filehandle, i.e., an opened file, from which we can read lines
        and loop over
    '''
    G = networkx.DiGraph()

    for line in fh:
        if not line.strip():  continue # move on to the next line,
                                         # if our line is empty-ish
        (subj,obj,verb) = split_on_verb(line)
        color = color_dict[verb]
        # cf: python 'string templates', there are other solutions here
        # this is the 
        print "'%s' -> '%s' [color='%s'];" % (subj,obj,color)
        G.add_edge(subj,obj,color)
        # 

    return G

G = graph_from_relationships(file('ex.txt'),rel_colors)
print G.edges()
# from here you can use the various networkx plotting tools on G, as you're inclined.

Python 2.5:

import sys
from collections import defaultdict

codes = defaultdict(lambda: ("---", "Missing action!"))
codes["likes"] =    ("-->", "red")
codes["dislikes"] = ("-/>", "green")
codes["loves"] =    ("==>", "blue")

for line in sys.stdin:
    subject, verb, object_ = line.strip().split(" ")
    arrow, color = codes[verb]
    print subject, arrow, object_, color, ";"

Además de la pregunta, Karasu también dijo (en un comentario sobre una respuesta):"En la entrada real, tanto los sujetos como los objetos varían de manera impredecible entre una y dos palabras".

Bien, así es como resolvería esto.

color_map = \
{
    "likes" : "red",
    "dislikes" : "blue",
    "knows" : "black",
}

def is_verb(word):
    return word in color_map

def make_noun(lst):
    if not lst:
        return "--NONE--"
    elif len(lst) == 1:
        return lst[0]
    else:
        return "_".join(lst)


for line in open("filename").readlines():
    words = line.split()
    # subject could be one or two words
    if is_verb(words[1]):
        # subject was one word
        s = words[0]
        v = words[1]
        o = make_noun(words[2:])
    else:
        # subject was two words
        assert is_verb(words[2])
        s = make_noun(words[0:2])
        v = words[2]
        o = make_noun(words[3:])
    color = color_map[v]
    print "%s -> %s %s;" % (s, o, color)

Algunas notas:

0) Realmente no necesitamos "con" para este problema, y ​​escribirlo de esta manera hace que el programa sea más portátil para versiones anteriores de Python.Creo que esto debería funcionar en Python 2.2 y versiones posteriores (solo probé en Python 2.6).

1) Puede cambiar make_noun() para tener cualquier estrategia que considere útil para manejar varias palabras.Mostré simplemente encadenándolos con guiones bajos, pero podrías tener un diccionario con adjetivos y descartarlos, tener un diccionario de sustantivos y elegirlos, o lo que sea.

2) También puedes usar expresiones regulares para lograr coincidencias más aproximadas.En lugar de simplemente usar un diccionario para color_map, podría tener una lista de tuplas, con una expresión regular emparejada con el color de reemplazo, y luego, cuando la expresión regular coincida, reemplazar el color.

Esta es una versión mejorada de mi respuesta anterior. Éste utiliza expresiones regulares para hacer una coincidencia parcial en el verbo. Todos estos trabajos:

Steve loves Denise
Bears love honey
Maria interested Anders
Maria interests Anders

El patrón de expresión regular "ama?" partidos "amor" más una opcional 's'. El patrón de "interés. *" Coincide con "interés" más cualquier cosa. Los patrones con múltiples alternativas separadas por barras verticales coinciden si cualquiera de las alternativas partidos.

import re

re_map = \
[
    ("likes?|loves?|interest.*", "red"),
    ("dislikes?|hates?", "blue"),
    ("knows?|tolerates?|ignores?", "black"),
]

# compile the regular expressions one time, then use many times
pat_map = [(re.compile(s), color) for s, color in re_map]

# We dont use is_verb() in this version, but here it is.
# A word is a verb if any of the patterns match.
def is_verb(word):
    return any(pat.match(word) for pat, color in pat_map)

# Return color from matched verb, or None if no match.
# This detects whether a word is a verb, and looks up the color, at the same time.
def color_from_verb(word):
    for pat, color in pat_map:
        if pat.match(word):
            return color
    return None

def make_noun(lst):
    if not lst:
        return "--NONE--"
    elif len(lst) == 1:
        return lst[0]
    else:
        return "_".join(lst)


for line in open("filename"):
    words = line.split()
    # subject could be one or two words
    color = color_from_verb(words[1])
    if color:
        # subject was one word
        s = words[0]
        o = make_noun(words[2:])
    else:
        # subject was two words
        color = color_from_verb(words[1])
        assert color
        s = make_noun(words[0:2])
        o = make_noun(words[3:])
    print "%s -> %s %s;" % (s, o, color)

Espero que sea claro cómo tomar esta respuesta y extenderlo. Usted puede agregar fácilmente más patrones para que coincida con más verbos. Se podría añadir la lógica para detectar "es" y "en" y desecharlos, por lo que "Anders está interesada en María" se correspondería. Y así sucesivamente.

Si usted tiene alguna pregunta, yo estaría dispuesto a explicar más a fondo. Buena suerte.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top