msmays5
Hola a todos,
Tengo una tabla de Palabras Requeridas con columnas [Template] y [Words].
Plantilla | Palabras |
Plantilla 1 | PERSONA;MUJER;HOMBRE |
Plantilla 2 | CÁMARA;TV |
Plantilla 3 | GATO PERRO |
yo tambien tengo la tabla 1[Value] que contiene texto libre. Mi objetivo es determinar si el texto en [Value] contiene todas las palabras de al menos una de las plantillas. Si bien actualmente no es un requisito devolver la plantilla que coincide, tengo la sensación de que podría cambiar en el futuro, por lo que sería una ventaja.
Valor | Resultado |
PERSONA texto aleatorio MUJER más texto aleatorio HOMBRE | Coincidencia (contiene las tres palabras de la plantilla 1) |
PERRO y CAMARA | Sin coincidencia (no contiene todas las palabras de ninguna de las plantillas) |
¡Muchas gracias por toda su ayuda!
mahoneypat
Aquí hay una forma de hacerlo con estas dos consultas de sus datos de ejemplo. También le muestra qué Plantilla tuvo la coincidencia (¿felicitaciones adicionales?). Para ver cómo funciona, simplemente cree una consulta en blanco, vaya al Editor avanzado y reemplace el texto allí con el código M a continuación.
Tenga en cuenta que M distingue entre mayúsculas y minúsculas, y esto funciona porque las palabras coincidentes estaban todas en MAYÚSCULAS. Si ese no es el caso con sus datos reales, agregue un paso para que todo esté en mayúsculas o minúsculas antes de las listas y comparaciones.
//call this one "Words"
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCknNLchJLElVMFTSUQpwDQr297MO9/d19LMGYqVYHSQVRkAVzo6+rkGO1iFhqFLGYKkQaxd/d6XYWAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Template = _t, Words = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Template", type text}, {"Words", type text}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "WordList", each Text.Split([Words], ";")),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Words"})
in
#"Removed Columns"
//call this one "Text"
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("VczBCsIwEIThVxlyUujFRyhaPDWVevAQegjtlghNVpIF9e1dWhG8/sx8zplL0187i+zTxBFCL8Gta2uLyJn+skZTmdbLGLAbOYm/pwK/LJCQifDkPBXwrOv4WLwQDnszVM6cujPUwbFum75WwzLixkxMBYkFX2/lNmjmrK/3Cgb6oUXN4QM=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Value = _t, Result = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Value", type text}, {"Result", type text}}),
#"Removed Other Columns" = Table.SelectColumns(#"Changed Type",{"Value"}),
#"Added Custom1" = Table.AddColumn(#"Removed Other Columns", "TextList", each Text.Split([Value], " ")),
#"Added Custom" = Table.AddColumn(#"Added Custom1", "Custom", each Words),
#"Expanded Custom" = Table.ExpandTableColumn(#"Added Custom", "Custom", {"Template", "WordList"}, {"Template", "WordList"}),
#"Added Custom2" = Table.AddColumn(#"Expanded Custom", "Match", each if List.ContainsAll([TextList], [WordList]) then "Yes" else "No"),
#"Removed Other Columns1" = Table.SelectColumns(#"Added Custom2",{"Value", "Template", "Match"})
in
#"Removed Other Columns1"
Si esto funciona para usted, por favor márquelo como la solución. También se agradecen los elogios. Por favor, hágamelo saber si no.
Saludos,
Palmadita
edhans
En respuesta a mahoneypat
@ msmays5: prueba esto. Dos tablas/consultas:
Esto se llama Words, y se ve así: comienza con su tabla inicial arriba, luego agregué una columna para convertirla en listas. Puede ver cómo se ve una de las listas incrustadas:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCknNLchJLElVMFTSUQpwDQr297MO9/d19LMGYqVYHSQVRkAVzo6+rkGO1iFhqFLGYKkQaxd/d6XYWAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Template = _t, Words = _t]),
#"Added Custom" = Table.AddColumn(Source, "WordList", each Text.Split([Words], ";"))
in
#"Added Custom"
La siguiente tabla es esta. También convierte sus oraciones en una lista, luego usa List.Generate para recorrer las listas de palabras (arriba). Un 1 significa que se encontró una coincidencia en una de las plantillas, 0 significa que no. Puede hacer lo que quiera con los registros 1/0 en ese punto.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCnANCvb3UyhKzEvJz1UoSa0oUQj393X0U8jNL0pFEQYKKsXqRCu5+LsrAIUVnB19XYMclWJjAQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Value = _t]),
#"Added Custom" = Table.AddColumn(Source, "AllWords", each Text.Split([Value], " ")),
ContainsWords =
Table.AddColumn(
#"Added Custom",
"Contains Words",
each
let
varCurrentWords = [AllWords],
varTemplates = Table.RowCount(Words)
in
Record.Field(
Record.Combine(
List.Generate(
() => [x = 0, y = 0],
each [x] < varTemplates,
each
[
y = if List.ContainsAll(varCurrentWords, Words[WordList]{[x]})
then [y] + 1
else [y],
x = [x] + 1
]
)
),
"y")
)
in
ContainsWords
Cómo usar el código M proporcionado en una consulta en blanco:
1) En Power Query, seleccione Nueva fuente, luego Consulta en blanco
2) En la cinta Inicio, seleccione el botón «Editor avanzado»
3) Elimina todo lo que ves, luego pega el código M que te he dado en ese cuadro.
4) Presiona Listo
5) Consulte este artículo si necesita ayuda para usar este código M en su modelo.
ziying35
Hola, @msmays5
Primero, convierta el formulario RequiredWords al siguiente formulario de listas
// RequiredWords
let
Source = Table.FromRecords(Json.Document(Binary.Decompress(Binary.FromText("i65WCknNLchJLElVsoIzFQyVdJTC84tSioGCAa5Bwf5+1uH+vo5+1kCsVKuDXZMRkiZnR1/XIEfrkDCcqo1RVIdYu/i7K9XGAgA=", BinaryEncoding.Base64),Compression.Deflate))),
trans = Table.TransformColumns(Source,{"Words", each Text.Split(_,";")}),
toRows = Table.ToRows(trans)
in
toRows
Luego, el código de consulta de Table1 se escribe así:
// Table1
let
Source = Table.FromRecords(Json.Document(Binary.Decompress(Binary.FromText("i65WCkvMKU1VslIKcA0K9vdTKErMS8nPVShJrShRCPf3dfRTyM0vSkURBgoq1eogdLr4uysApRWcHX1dgxxxSIXoQOXB/JAwpdpYAA==", BinaryEncoding.Base64),Compression.Deflate))),
result = Table.AddColumn(
Source,
"Result",
(r)=>let match_template = Text.Combine(
List.Transform(
RequiredWords,
each if List.ContainsAll({r[Value]}, _{1}, Text.Contains) then _{0} else null
),
", "
)
in if match_template ="" then "No match" else "Match: " & match_template
)
in
result
La tabla Table1 convertida se muestra a continuación:
ziying35
Hola, @msmays5
Primero, convierta el formulario RequiredWords al siguiente formulario de listas
// RequiredWords
let
Source = Table.FromRecords(Json.Document(Binary.Decompress(Binary.FromText("i65WCknNLchJLElVsoIzFQyVdJTC84tSioGCAa5Bwf5+1uH+vo5+1kCsVKuDXZMRkiZnR1/XIEfrkDCcqo1RVIdYu/i7K9XGAgA=", BinaryEncoding.Base64),Compression.Deflate))),
trans = Table.TransformColumns(Source,{"Words", each Text.Split(_,";")}),
toRows = Table.ToRows(trans)
in
toRows
Luego, el código de consulta de Table1 se escribe así:
// Table1
let
Source = Table.FromRecords(Json.Document(Binary.Decompress(Binary.FromText("i65WCkvMKU1VslIKcA0K9vdTKErMS8nPVShJrShRCPf3dfRTyM0vSkURBgoq1eogdLr4uysApRWcHX1dgxxxSIXoQOXB/JAwpdpYAA==", BinaryEncoding.Base64),Compression.Deflate))),
result = Table.AddColumn(
Source,
"Result",
(r)=>let match_template = Text.Combine(
List.Transform(
RequiredWords,
each if List.ContainsAll({r[Value]}, _{1}, Text.Contains) then _{0} else null
),
", "
)
in if match_template ="" then "No match" else "Match: " & match_template
)
in
result
La tabla Table1 convertida se muestra a continuación:
msmays5
En respuesta a ziying35
¡Gracias, @ziying35! Hay una complicación de la que no estaba al tanto (¡que su respuesta resuelve!), Que es cómo manejar las frases requeridas. (@edhans y @mahoneypat, mis disculpas por no darme cuenta de esa necesidad; estoy seguro de que ambos tendrían excelentes soluciones para eso también, pero debido a que se dividieron en el espacio, sus soluciones no funcionaron para este requisito completamente cambiado)
Una cosa que no funcionaba con la solución @ ziying35 es que para la Plantilla 1, la palabra HOMBRE no es realmente necesaria para devolver un valor; este valor «MUJER abc PERSONA DEL AÑO» devuelve verdadero aunque la palabra HOMBRE no esté incluida. Para solucionar esto, agregué y añadí un espacio a los campos Palabras y Valor requeridos para asegurarme de que sean palabras únicas. Muchas gracias a todos por su ayuda, esta es una gran comunidad
ziying35
En respuesta a msmays5
@msmays5
Prueba esto:
// RequiredWords
let
Source = Table.FromRecords(Json.Document(Binary.Decompress(Binary.FromText("i65WCknNLchJLElVsoIzFQyVdJTC84tSioGCAa5Bwf5+1uH+vo5+1kCsVKuDXZMRkiZnR1/XIEfrkDCcqo1RVIdYu/i741JrgqTUyLC4BOKKWAA=", BinaryEncoding.Base64),Compression.Deflate))),
trans = Table.TransformColumns(Source,{"Words", each Text.Split(_,";")}),
toRows = Table.ToRows(trans)
in
toRows
// Table1
let
Source = Table.FromRecords(Json.Document(Binary.Decompress(Binary.FromText("i65WCkvMKU1VslIKcA0K9vdTKErMS8nPVShJrShRCPf3dfRTyM0vSkURBgoq1eogdLr4uysApRWcHX1dgxxxSIXoQOXB/JAwFGUQi6AKccgYGRaXoEghS4AMd1GqjQUA", BinaryEncoding.Base64),Compression.Deflate))),
result = Table.AddColumn(
Source,
"Result",
(r)=>let match_template = Text.Combine(
List.Transform(
RequiredWords,
each if List.ContainsAll(Text.SplitAny(r[Value], Text.Remove(Text.Combine({" ".."@"}), {"0".."9"})) , _{1}) then _{0} else null
),
", "
)
in if match_template ="" then "No match" else "Match: " & match_template
)
in
result
mahoneypat
Aquí hay una forma de hacerlo con estas dos consultas de sus datos de ejemplo. También le muestra qué Plantilla tuvo la coincidencia (¿felicitaciones adicionales?). Para ver cómo funciona, simplemente cree una consulta en blanco, vaya al Editor avanzado y reemplace el texto allí con el código M a continuación.
Tenga en cuenta que M distingue entre mayúsculas y minúsculas, y esto funciona porque las palabras coincidentes estaban todas en MAYÚSCULAS. Si ese no es el caso con sus datos reales, agregue un paso para que todo esté en mayúsculas o minúsculas antes de las listas y comparaciones.
//call this one "Words"
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCknNLchJLElVMFTSUQpwDQr297MO9/d19LMGYqVYHSQVRkAVzo6+rkGO1iFhqFLGYKkQaxd/d6XYWAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Template = _t, Words = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Template", type text}, {"Words", type text}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "WordList", each Text.Split([Words], ";")),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Words"})
in
#"Removed Columns"
//call this one "Text"
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("VczBCsIwEIThVxlyUujFRyhaPDWVevAQegjtlghNVpIF9e1dWhG8/sx8zplL0187i+zTxBFCL8Gta2uLyJn+skZTmdbLGLAbOYm/pwK/LJCQifDkPBXwrOv4WLwQDnszVM6cujPUwbFum75WwzLixkxMBYkFX2/lNmjmrK/3Cgb6oUXN4QM=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Value = _t, Result = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Value", type text}, {"Result", type text}}),
#"Removed Other Columns" = Table.SelectColumns(#"Changed Type",{"Value"}),
#"Added Custom1" = Table.AddColumn(#"Removed Other Columns", "TextList", each Text.Split([Value], " ")),
#"Added Custom" = Table.AddColumn(#"Added Custom1", "Custom", each Words),
#"Expanded Custom" = Table.ExpandTableColumn(#"Added Custom", "Custom", {"Template", "WordList"}, {"Template", "WordList"}),
#"Added Custom2" = Table.AddColumn(#"Expanded Custom", "Match", each if List.ContainsAll([TextList], [WordList]) then "Yes" else "No"),
#"Removed Other Columns1" = Table.SelectColumns(#"Added Custom2",{"Value", "Template", "Match"})
in
#"Removed Other Columns1"
Si esto funciona para usted, por favor márquelo como la solución. También se agradecen los elogios. Por favor, hágamelo saber si no.
Saludos,
Palmadita
edhans
En respuesta a mahoneypat
@ msmays5: prueba esto. Dos tablas/consultas:
Esto se llama Words, y se ve así: comienza con su tabla inicial arriba, luego agregué una columna para convertirla en listas. Puede ver cómo se ve una de las listas incrustadas:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCknNLchJLElVMFTSUQpwDQr297MO9/d19LMGYqVYHSQVRkAVzo6+rkGO1iFhqFLGYKkQaxd/d6XYWAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Template = _t, Words = _t]),
#"Added Custom" = Table.AddColumn(Source, "WordList", each Text.Split([Words], ";"))
in
#"Added Custom"
La siguiente tabla es esta. También convierte sus oraciones en una lista, luego usa List.Generate para recorrer las listas de palabras (arriba). Un 1 significa que se encontró una coincidencia en una de las plantillas, 0 significa que no. Puede hacer lo que quiera con los registros 1/0 en ese punto.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCnANCvb3UyhKzEvJz1UoSa0oUQj393X0U8jNL0pFEQYKKsXqRCu5+LsrAIUVnB19XYMclWJjAQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Value = _t]),
#"Added Custom" = Table.AddColumn(Source, "AllWords", each Text.Split([Value], " ")),
ContainsWords =
Table.AddColumn(
#"Added Custom",
"Contains Words",
each
let
varCurrentWords = [AllWords],
varTemplates = Table.RowCount(Words)
in
Record.Field(
Record.Combine(
List.Generate(
() => [x = 0, y = 0],
each [x] < varTemplates,
each
[
y = if List.ContainsAll(varCurrentWords, Words[WordList]{[x]})
then [y] + 1
else [y],
x = [x] + 1
]
)
),
"y")
)
in
ContainsWords
Cómo usar el código M proporcionado en una consulta en blanco:
1) En Power Query, seleccione Nueva fuente, luego Consulta en blanco
2) En la cinta Inicio, seleccione el botón «Editor avanzado»
3) Elimina todo lo que ves, luego pega el código M que te he dado en ese cuadro.
4) Presiona Listo
5) Consulte este artículo si necesita ayuda para usar este código M en su modelo.
msmays5
En respuesta a edhans
@mahoneypat @edhans ¡Gracias a ambos por sus rápidas respuestas! Ambos funcionaron perfectamente (¡y @mahoneypat, felicitaciones adicionales por devolver el nombre de la plantilla!)
greg_deckler
@ msmays5 – Siento que necesitará Text to Table – https://community.powerbi.com/t5/Quick-Measures-Gallery/Text-to-Table/td-p/1312929
Más allá de eso, tendré que trabajar un poco, pero creo que eso lo guiará en la dirección correcta y puede llegar a lo que desea antes de que tenga tiempo de sentarme y trabajarlo en detalle.
msmays5
En respuesta a greg_deckler
Gracias @Greg_Deckler por tu rápida respuesta, le echaré un vistazo. Lo que vinculó fue DAX (a lo que no me opongo, pero estaba pensando en abordar esto en PQ para poder devolverlo a un flujo de datos). El texto que necesito analizar es largo y tiene una cardinalidad muy alta, por lo que prefiero identificar si el texto coincide con una plantilla (ya sea que regrese como lógico o si devolvemos el nombre de la plantilla, al menos debería tener una cardinalidad baja) y luego soltar el texto libre [Value] columna.