Power BI Table Transformation - powerbi

I am trying to find a way in Power BI to transform a table into a specific format for a custom visualization. The transformation that I'd like to do is the following image:
Is this possible to do? I've thought of unpivoting or transposing but haven't seemed to figure out how to get past this point.

I do not really understand the use case of this transformation, but you can achieve what you want by copying the source table, remove all columns except 2, and then append all copies.
Let's say we have one table, named Table, like this:
Make 3 copies of the table, by clicking New Source -> Blank Query:
and enter =Table as query text, where Table is the name of our source table. If our queries are named Query1, Query2 and Query3, then click on each of them and remove the extra column and keep A and B in Query1, keep B and C in Query2, and C and D in Query3. Rename the remaining columns to be named the same way in all 3 queries and click Append Queries or Append Queries as New, then select the 3 copes:
This will give you the result you ask for:
Or you could do it in one go, without creating three different queries. Makes your Queries pane a bit nitter
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUXICYmcgdlGKjQUA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [c1 = _t, c2 = _t, c3 = _t, c4 = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"c1", type text}, {"c2", type text}, {"c3", type text}, {"c4", type text}}),
_t1 = Table.SelectColumns(#"Changed Type", {"c1", "c2"}),
_t1_r = Table.RenameColumns(_t1, {{"c1", "ca"}, {"c2", "cb"}}),
_t2 = Table.SelectColumns(#"Changed Type", {"c2", "c3"}),
_t2_r = Table.RenameColumns(_t2, {{"c2", "ca"}, {"c3", "cb"}}),
_t3 = Table.SelectColumns(#"Changed Type", {"c3", "c4"}),
_t3_r = Table.RenameColumns(_t3, {{"c3", "ca"}, {"c4", "cb"}}),
_res = Table.Combine({_t1_r, _t2_r, _t3_r})
in
_res

One use case I can think of this transformation will be useful is that, when we have a time series data like this, and we want to compare the values of current and last periods.
So here is a version for the case when the number of columns is variable.
let
Source = ...,
SingleRow = Table.SingleRow(Source),
Values = Record.FieldValues(SingleRow),
Pairs = List.Zip({List.RemoveLastN(Values, 1), List.RemoveFirstN(Values, 1)}),
Result = Table.FromRows(Pairs, {"Last", "Current"})
in
Result

I am implying the "rules" for this transformation are then you want a table where the first column and second column form each "pair" of items in the original set. Given the data loaded into Power Query like this:
I would transpose the data:
Then make two references to the query. In the first one remove the last row, in the second one remove the first row. Then add an index column to both.
(result of the first reference looks like this)
Then just do a merge between the two references and you get the two column outputs show in the example.

Related

How to unpivot specific columns of the table using DAX?

Hey, so a novice here. I dont want the data to be leaked so I have hidden it and marked it with tags though.
Basically what you are looking at is the accuracy data of a classification model. As you can see, for some classes like "A" it predicts all data points correctly, thus it is flagged as True, but we dont have a False column for A because there are no False values. For some reason when we created this table in DAX by grouping a couple of columns and performing the count operation on different table,DAX didnt show False for any values that were completely True.
On the other hand, for "D", 185 values are true and 2 values are false.
We need to showcase this as like a bar chart with maybe a slicer for the different categories. For that we first need the "False" attribute for the values that predicted completely true, then we need to compute the percentage of False and True predictions for each class and then we need to show that in a bar chart.
We are thinking we should pivot the "FLAG" and the "Predicted Values" column for this, and then we will be able to do all the things aforementioned. But because this table was created using DAX from another table, we are unable to find a way to pivot it. It wont evens how up in the Power Query editor. Any tips or help are welcomed. Sorry again, Im a novice so just learning as I work..
You don't need to pivot. You need a flag dimension table joined to your existing table on flag. The dimension contains just two values for true and false and the cardinality is one-to-many unidirectional. Then on your bar chart, make sure to check show items with no data in the field well.
Starting with : (Using enter data and copy paste from excel)
Adding the following code in the advanced editor under Transforme Data:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WSlTSUQoJCnUFUkbmJsYWSrE60UpJCEFDAzOwUDJCyMTUFCyUgqTKAiHk5ugTDDYOLJKKpMjMBCyUhmy6BVwIps8QLJKOpMjUHCyUgSRkbAJXBdNnAnFoJpIQxFFZqI6KBQA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, Flag = _t, Value = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"category", type text}, {"Flag", type logical}, {"Value", Int64.Type}}),
#"Pivoted Column" = Table.Pivot(Table.TransformColumnTypes(#"Changed Type", {{"Flag", type text}}, "en-SE"), List.Distinct(Table.TransformColumnTypes(#"Changed Type", {{"Flag", type text}}, "en-SE")[Flag]), "Flag", "Value", List.Sum)
in
#"Pivoted Column"
Gives:
Which is what I assume you are after

Create idex with repeated data

I have data from an external source that is downloaded in csv format. This data shows the interactions from several users and doesn't have an id column. The problem I'm having is that I'm not able to use index because multiple entries represent interactions and processes. The interactions would be the group of processes a specific user do and the process represents each actions taken in a specific interaction. Any user could repeat the same interaction at any time of day. The data looks likes this:
User1 has 2 processes but there were 3 interactions. How can I assign an ID for each interaction having into consideration that there might be multiple processes for a single user in the same day. I tried grouping them in Power Query but it groups the overall processes and I'm not able to distinguish the number of interactions. Is it better to do it in Dax?
Edit:
I notice that it is hard to understand what I need but I think this would be a better way to see it:
Process 2 are the steps done in an interaction. Like in the column in yellow I need to add an ID taking in to consideration where an interaction start and where it ends.
I'm not exactly sure I follow what you describe. It looks to me like user1 has 4 interactions--Processes AA, AB, BA, and BB--but you say 3.
Still, I decided to take a shot at providing an answer anyway. I started with a CSV file set up like you show.
Then brought the CSV into Power Query and, just to add a future point of reference so that you could follow the Id assignments better, I added an index column that I called startingIndex.
Then I added a custom column combining the processes that I understand actually define an interaction.
Then I grouped everything by users and Interactions into a column named allData.
Then I added a custom column to copy the column that was created from the earlier grouping, to sort the tables within it, and to add an index to each table within it. This essentially indexed each user's interaction group. (Because all of your interactions occur on the same date(s), the sorting doesn't help much. But I did it to show where you could do it if you included datetime info instead of just a date.)
Then I added a custom column to copy the column that was created earlier to add the interactions index, and to add an Id item within each table within it. I constructed each Id by combining the user, interactions, and interactionIndex for each.
Then I selected the latest column I had created (complexId) and removed all other columns.
Last, I expanded all tables without including the Interactions and Index columns. (The Index column was the index used for the interactions within the groups and no longer needed.) I included the startingIndex column just so you could see where items originally were at the start, in comparison to their final Id.
Given your new example, to create the Interaction ID you show, you only need the first two columns of the table. If not part of the original data, you can easily generate the third column (Process2))
It appears you want to increment the interaction ID whenever the Process changes
Please read the comments in the M code and explore the Applied Steps to better understand the algorithm:
M Code
let
//be sure to change table name in next row to your real table name
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"User", type text},
{"Process", type text},
{"Process2", type text}
}),
//add an index column
idx = Table.AddIndexColumn(#"Changed Type", "Index", 0, 1, Int64.Type),
//Custom column returns the Index if
// the current Index is 0 (first row) or
// there has been no change in user or process comparing current/previous row
// else return null
#"Added Custom" = Table.AddColumn(idx, "Custom",
each if [Index]=0
then 0
else
if [Process] <> idx[Process]{[Index]-1} or [User] <> idx[User]{[Index]-1} then [Index]
else null),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Index"}),
//Fill down the custom column
// now have same number for each interactive group
#"Filled Down" = Table.FillDown(#"Removed Columns",{"Custom"}),
//Group by the "filled down" custom column with no aggregation
#"Grouped Rows" = Table.Group(#"Filled Down", {"Custom"}, {
{"all", each _, type table [User=nullable text, Process=nullable text, Process2=nullable text, Custom=number]}
}),
//add a one-based Index column to the grouped table
#"Added Index" = Table.AddIndexColumn(#"Grouped Rows", "Interaction ID", 1, 1, Int64.Type),
#"Removed Columns1" = Table.RemoveColumns(#"Added Index",{"Custom"}),
//Re-expand the table
#"Expanded all" = Table.ExpandTableColumn(#"Removed Columns1", "all",
{"User", "Process", "Process2"}, {"User", "Process", "Process2"})
in
#"Expanded all"
Source
Results

Power Query - trying to remove a dynamic column that's created/updated when I access external data source

I have a table that's generated when I pull data from an accounting software - the example columns are months/years in the format as follows (It pulls all the way to current day, and the last month will be partial month data):
Nov_2020
Dec_2020
Jan_2021
Feb_1_10_2021 (Current month, column to remove)
... So on and so forth.
My goal I have been trying to figure out is how to use the power query editor to remove the last column (The partial month) - I tried messing around with the text length to no avail (The goal being to remove anything with text length >8, so the full months data would show but the last month shouldn't). I can't just remove based on a text filter, because if someone were to pull the data 1 year from now it would have to account for 2021/2022.
Is this possible to do in PQ? Sorry, I'm new to it so if I need to elaborate more I can.. Thanks!
You can do this with Table.SelectColumns where you use List.Select on the Table.ColumnNames.
= Table.SelectColumns(
PrevStep,
List.Select(Table.ColumnNames(PrevStep), each Text.Length(_) <= 8)
)
Although both Alexis Olson's and Justyna MK's answers are valid, there is another approach. Since it appears that you're getting data for each month in a separate column, what you will surely want to do is unpivot your data, that is transform those columns into rows. It's the only sensible way to get a good material for analysis, therefore, I would suggest to unpivot the columns first, then simply filter out rows containing the last month.
To make it dynamic, I would use unpivot other columns option - you select columns and it will transform remaining columns into row in such a way that two columns will be created - one that will contain column names in rows and the other one will contain values.
To illustrate what I mean by unpivoting, when you have data like this:
You're automatically transforming that into this:
You can try to do it through Power Query's Advanced Editor. Assign the name of the last column to LastColumn variable and then use it in the last step (Removed Columns).
let
Source = Excel.Workbook(File.Contents(Excel file path), null, true),
tblPQ_Table = Source{[Item="tblPQ",Kind="Table"]}[Data],
#"Changed Type" = Table.TransformColumnTypes(tblPQ_Table,{{"Nov_2020", Int64.Type}, {"Dec_2020", Int64.Type}, {"Jan_2021", Int64.Type}, {"Feb_1_10_2021", Int64.Type}}),
LastColumn = List.Last(Table.ColumnNames(#"Changed Type")),
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{LastColumn})
in
#"Removed Columns"

Power Query - Find and replace in one step instead of several

I have a simple column here.
I am using Power Query to replace some values,
1 becomes 119, 2 becomes 201, 3 becomes 321
There are no particular logic to it, it's to correct the mistyped numbers by users.
I did a find a replace function.
Table.ReplaceValue(#"Changed Type",1,119,Replacer.ReplaceValue,{"Name"}) which worked great.
I want to combine the other find and replace functions into one single step for cleaner code.
I tried this but didn't work.
Table.ReplaceValue(#"Changed Type",{1,2},{119,201},Replacer.ReplaceValue,{"Name"})
I don't want to have 10 different find and replace steps in my PQ just want to have one step.
OPTION-1
Here below is the M code for all replace together-
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMlSK1YlWMgKTxkqxsQA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Column1 = _t]),
#"AllReplace" = [
#"1" = "119",
#"2" = "201",
#"3" = "321"
],
#"Replaced Value" = Table.TransformColumns(Source,{{"Column1",each Record.FieldOrDefault(AllReplace,_,_)}})
in
#"Replaced Value"
Note: Need to number column as Text. You can convert the column to Number after the Replace Step.
Input
Output
OPTION-2:
You can also create a custom column using the below code-
if [Column1] = 1 then 119 else if [Column1] = 2 then 201 else 321
After creating the custom column, you can keep or remove the source coulmn.

Define report in PowerBI where columns change over time

I have a HTML file that is generated daily. Over the past few years we have added a couple of columns to the HTML table in the file. What I want to do is generate some reports that trend over time based on that HTML, so I want to define a single query for a report, but get a null/default value when the column isn't present in the source.
I have a list of report dates that are available and then I can add copies of the report data to a master report. The data source however fails to load if the column isn't present in the older reports. Essentially I read a date from one HTML file as an input, then modify the fetch URL per row for the source to get the historical data.
Is it possible to generate this report without retrospectively changing the old data and adding the column that is missing? I couldn't see how to do this easily.
I've never done anything like that, but maybe something like this will help.
It checks if a column exists and if it does not then create a new column with a default value.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMlTSUUpUitWJVjICspLALGMgK1kpNhYA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [AA = _t, BB = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"AA", Int64.Type}, {"BB", type text}}),
#"Custom1" = if Table.HasColumns(#"Changed Type",{"MissingColumn1"}) = false
then Table.AddColumn(#"Changed Type","MissingColumn1", each "<n/d>")
else #"Changed Type"
,#"Custom2" = if Table.HasColumns(#"Custom1",{"MissingColumn2"}) = false
then Table.AddColumn(#"Custom1","MissingColumn2", each "<n/d>")
else #"Custom1"
,#"Custom3" = if Table.HasColumns(#"Custom2",{"MissingColumn3"}) = false
then Table.AddColumn(#"Custom2","MissingColumn3", each "<n/d>")
else #"Custom2"
in
#"Custom3"
If this is a suitable solution depends on how data are fetched from the source.