주어진 카테고리의 값을 예측하는 일별 파일이 수신됩니다. FileDate = FcstDate 인 경우 값 FcstVal은 실제로 실제의 실제 값입니다. 지금 Excel Power Query (XL'16 : Get & Transform)를 사용하여 수십 개의 파일을 아래 (400k + 행, 실제로는 18 레벨)와 유사한 테이블로 쉽게 가져옵니다. 1-3 (44)는 각각 널 (60)이 될 것으로 예상했지만, 실제 값은 다른 모든 위해 43 동감이었다 | AC가 |예측 된 값을 실제 값으로 일치
나는 1-1에서 1-2 종류 AA, 말할 수 있어야합니다 열. 대부분은 아니지만 모든 고유 한 행 조합은 파일간에 공통입니다. 결국 변경된 레벨을 처리하는 것에 대해 걱정해야 할 것입니다 ...
Table.Partition, Table.FillUp, Table.FromPartitions Power Query 함수는 로직을 완벽하게 나타내지 만 Power Query는 너무 느립니다. 내가 & 예보가 분할 날짜 모든 별개의 범주 수준으로 인덱스 테이블을 필요할 것 때문에 (행 당 + 1 배!이) 악화 각 매우 큰 .XLSX 파일을 여러 번 읽어 보시기 바랍니다. =SUMIFS([ActualVal], [Lvl1],[@[Lvl1]], [Lvl2],[@[Lvl2]], [Lvl3],[@[Lvl3]], [FileDt]],[@[FcstDt]], [@[Eq]]="Y")
그러나이 "="또는 ">", 등을 시작 '널 (NULL)', 변경 값으로 모두 공백 설정 필요 지금 나 엑셀 표에서 공식을 이용하여 감소하고있어
계산에 시간 걸립니다.
내가 효율적 & 큰 데이터 세트를 계산 필터링 할 수있어 이해하기 때문에의 PowerPivot/DAX를 배우려고 노력했습니다. DAX 계산의 '컨텍스트'를 구식 엑셀 수식을 통해 참조하는 동일한 행으로 설정하는 솔루션을 기대합니다. & 값을 '원한'열로 이동합니다. 그러나 그것을 이해하지 못했습니다. .
나는 가능하면 많이가 된 PowerPivot 솔루션을 선호 싶지만,하지 않을 경우, 가끔 파이썬/팬더의 감각을 만들 수 있습니다. 그러나 타사 제공 업체의 Excel 입력에 문제가 있습니다.Lvl1 | Lvl2 | Lvl3 | FileDt | FcstDt | Eq | FcstVal | ActualVal | Wanted! 1-1: ________________________________________________________________________ AA AB AD 1-1 1-1 Y 100 100 100 AA AC AE 1-1 1-1 Y 50 50 50 AA AB (null) 1-1 1-2 110 105 AA AC (null) 1-1 1-2 (null) 45 AA AB (null) 1-1 1-3 120 105 AA AC (null) 1-1 1-3 70 43 1-2 file: ___________________________________________________________________ AA AB (null) 1-2 1-2 Y 105 105 105 AA AC (null) 1-2 1-2 Y 45 45 45 AA AB (null) 1-2 1-3 113 (null) AA AC (null) 1-2 1-3 44 43 1-3 file: ___________________________________________________________________ (missing row AA|AB!) 1-3 1-3 Y (null) (null) (null) AA AC (null) 1-3 1-3 Y 43 43 43 AA AB (null) 1-3 1-4 108 (null) AA AC (null) 1-3 1-4 42 (null)
편집 :
일부가 다른 사람에게 도움이 될 수 있기 때문에 내 코드를 공유합니다, 내 문제는 다른 부분에있을 수 있습니다.
내 전략이라는 오픈 Excel에서 테이블 당으로 통합 문서의 집합을로드하는 것입니다. 간단한 함수를 적용하여 통합 문서 내용에서 원하는 테이블을 추출한 다음 테이블에서 가능한 한 많은 처리를 수행하는 함수를 적용하여 여전히 분리 된 상태에서 멀티 스레딩이 여전히 독립적이므로 더 잘 활용 될 수 있다고 생각합니다. 그게 맞습니까?).
첫 번째 쿼리 :가 종료됩니다. 나는 여기서 멈추고 PowerPivot이 나머지를 할 수 있다면 (필요한 경우 최종 Table.Combine으로) 선호한다.
Power Query에서 필자는 테이블을 두 번 결합해야합니다. 첫 번째 필드에는 모든 필드가 있고 두 번째 필드에는 값 또는 As-Date 필드가없는 모든 테이블의 고유 한 그룹화 필드가 있습니다. 그룹화 조합이 첫 번째 테이블에없는 후속 테이블에 존재할 수 있기 때문에 단일 (즉, 첫 번째) 테이블을 사용할 수 없습니다. 그 반대의 경우도 마찬가지입니다. & 이 고유 표는 색인을 얻습니다.
난 Table.NestedJoin & 추출물 통해 제 내지 제 접합부 열의 인덱스 만 가입. 이를 통해 데이터를 동일한 예측일 & 그룹 만있는 파티션으로 나눌 수 있습니다.PrepareData_Table 함수에서 날짜순으로 내림차순으로 테이블을 미리 정렬했기 때문에 FillDown을 사용할 수 있습니다. 따라서 실제 값이 같은 그룹의 다른 그룹으로 이동하면 더 이상 없습니다.
이 후에는 테이블을 간단히 재결합하십시오.
CODE :
는 FieldMetadata 데이터 유형 &에게 필드에 대한 주문 정보를 보유하고 있습니다. 소스에는 지정된 파일을로드할지 여부를 지정하는 경로 이름 &이 있습니다.
ImportParameters :
[ThisWB = Excel.CurrentWorkbook()
Sources = ThisWB{[Name="Sources"]}[Content],
FieldMetadata = ThisWB{[Name="FieldMetadata"]},
FieldTypes = Table.ToRows(GetCfg({"Type"})),
CategoryFields = List.Buffer(List.Transform(List.Select(List.Transform(FieldTypes, each {List.First(_), TypeFromString(List.Last(_))}), each List.Last(_) = type text), each List.First(_))),
CategoryFieldTypes = List.Buffer(List.Transform(FieldTypes, (_) => {List.First(_), TypeFromString(List.Last(_))}))
GetCfg :
let
Cfg = (Columns as list) as table =>
let
FilterList = List.Transform(Columns, each "[" & _ & "]" <> null"),
ExpressionText = Text.Combine(FilterList, " and "),
Source = Excel.CurrentWorkbook(){Name="FieldMetadata"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source, {{"Field", type text}, {"Type", type text"}, {"Grouping", Int32.Type}, {"Presentation"}, Int32.Type}}),
Custom1 = Table.SelectColumns(#"Changed Type", List.Combine({{"Field"}, Columns})),
#"Filtered Rows" = Table.SelectRows(Custom1, each Expression.Evaluate(ExpressionText, [_=_]))
/* The above line is a bit of a mind bender. It lets me apply filteres without hard-coding column names. Very useful.
Credit to http://www.thebiccountant.com/2016/03/08/select-rows-that-have-no-empty-fields-using-expression-evaluate-in-power-bi-and-power-query/
*/
in
#"Filtered Rows"
in
Cfg
FieldSortOrder
let
SortOn = (SortOn as text) as list =>
let
Source = ImportParameters[FieldMetadata],
#"Changed Type" = Table.TransformColumnTypes(Source, {{"Field", type text}, {"Grouping", type number}}),
SelectedSort = Table.SelectXolumns(Source, {"Field", SortOn}),
RenamedSortColumn = Table.RenameColumns(SelectedSort, {{SortOn, "Sort"}}),
NoNulls = Table.SelectRows(RenamedSortColumn, each ([Sort] <> null)),
SortedFields = Table.Sort(NoNulls, {{"Sort", Order.Ascending}})[Field]
in
SortedFields
in
SortOn
TypeFromString
let
Type = (TypeName as text) as type =>
let
TypeNameFix = if TypeName = "Table" then "_Table" else TypeName, // because Table is a reserved word
TypR = [Any=Any.Type,
Binary=Binary.Type, // The whole list of types I could find.
...
_Table=Table.Type,
...
WebMethod=WebMethod.Type],
TheType = try Record.Field(TypR, TypeNameFix) otherwise error [Reason="TypeName not found", Message="Parameter was not found among the list of types defined within the TypeFromString function.",
in
TheType
in
Type
,174,
Extract_Data_Table :
let
Source = (Table as table) as table =>
let
#"Filtered Rows" = Table.SelectRows(Table, each ([Kind] = "Table" and ([Item] = "Report Data" or [Item] = "Report_Data"))),
#"Select Columns" = Table.SelectColumns(#"Filtered Rows", "Data"),
DataTable = #"Select Columns"[Data]{0}
in
DataTable
in
Source
Prep_Data_Table :
let
PrepParams = (HorizonEnd as date, CategoryFieldTypes as list) as function =>
let
HorizonEnd = HorizonEnd,
CategoryFieldTypes = List.Buffer(CategoryFieldTypes),
Source = (InputTable as table, FileDate as date) as table =>
let
EndFields = {"As-of Date", "PERIOD", "Actual", "Forecast"} as list,
PeriodsAsDates = Table.TransformColumnTypes(InputTable, {{"PERIOD", type date}}),
#"Remove Errors" = Table.RemoveRowsWithErrors(PeriodsAsDates, {"PERIOD"}),
WithinHorizon = Table.SelectRows(#"Remove Errors", each ([PERIOD] <= HorizonEnd)),
RenamedVAL = Table.RenameColumns(WithinHorizon, {"VAL", "Forecast"}), // Forecast was originally named VAL
MovedActual = Table.AddColumn(RenamedVAL, "Actual", each if [PERIOD]=FileDate then (if [Forecast] is null then 0 else [Forecast]) else null),
IncludesOfDate = Table.AddColumn(MovedActual, "As-of Date", each FileDate, Date.Type),
AppliedCategoryFieldTypes = Table.TransformColumnTypes(IncludeAsOfDate, CategoryFieldTypes),
TransformedColumns = Table.TransformColumns(AppliedCategoryFieldTypes, {{"{Values}", Text.Trim, type text}, {"Actual", Number.Abs, Currency.Type}, {"Forecast", Number.Abs, Currency.Type}}),
Sorted = Table.Sort(TransformedColumns, {{"Actual", Order.Descending}}), // Descending order is important because Table.FillDown is more efficient than Table.FillUp
OutputTable = Table.SelectColumns(Sorted, List.Distinct(List.Combine({List.Transform(CategoryFieldTypes, each List.First(_)), EndFields}))),
Output = OutputTable
in
Output
in
Source
in
PrepParams
통합 문서 :
let
// Import Data
Source = ImportParameters[Sources],
#"Changed Type" = Table.TransformColumnTypes(Source, {{"As-of Date", type date}, {"Folder Path", type text}, {"Tab", type text}, {"Load", type logical}}),
#"Filtered Rows"= Table.SelectRows(#"Changed Type", each ([Load] = true)),
WorkbookPaths = Table.AddColumn(#"Filtered Rows", "File Path", each [Folder Path] & [File], type text),
LoadWorkbooks = Table.AddColumn(WorkbookPaths, "Data", each Excel.Workbook(File.Contents([File Path])) meta [#"As-of Date" = [#"As-of Date"]]),
LoadDataTables = Table.TransformColumns(LoadWorkbooks, {"Data", each Extract_Data_Table(_) meta [#"As-of Date" = Value.Metadata(_)[#"As-of Date"]]}),
PrepFunc = Prep_Data_Table(List.Max(LoadDataTables[#"As-of Date"]), ImportParameters[CategoryFieldTypes]),
// This TransformColumns step references the column's list, not the table, so the As-of Date field of the column is out of scope. Use metadata to bring the As-of Date value into the same scope
PrepDataTables = Table.TransformColumns(LoadDataTables, {"Data", each Table.Buffer(PrepFunc(_, Value.Metadata(_)[#"As-of Date"]))}),
Output = Table.SelectColumns(PrepDataTables, {"Data", "As-of Date"})
in
Output
MakeComparison :
let
CategoryFields = ImportParameters[CategoryFields]
DataTableList = Workbooks[Data],
CategoryIndex = Table.AddIndexColumn(Table.Distinct(Table.Combine(List.Transform(DataTableList, each Table.SelectColumns(_, CategoryFields)))), "Index"),
ListOfDataTablesWithNestedIndexTable = List.Transform(DataTableList, each Table.NestedJoin(_, CategoryFields, CategoryIndex, CategoryFields, "Index", JoinKind.Inner)),
ListOfIndexedDataTables = List.Transform(ListOfDataTablesWithNestedIndexTable, each Table.TransformColumns(_, {"Index", each List.Single(Table.Column(_, "Index")) as number, type number})),
Appended = Table.Combine(ListOfIndexedDataTables),
Merged = Table.Join(CategoryIndex, "Index", Table.SelectColumns(Appended, {"As-of Date", "Actual", "Forecast", "Index"}), "Index"),
Partitioned = Table.Partition(Merged, "Index", Table.RowCount(CategoryIndex), each _),
CopiedActuals = List.Transform(Partitioned, each Table.FillDown(_, {"Actual"})),
ToUnpartition = List.Transform(CopiedActuals, each {List.First(_[Index]), Table.RemoveColumns(_, {"Index"})}),
UnPartitioned = Table.FromPartitions("Index", ToUnpartition, type number),
Output = Unpartitioned
in
Output
질문 : 클로저로서 자격이 있습니까?
질문 : Table.FromPartitions를 사용하는지 또는 단순히 Table.Combine을 사용하여 테이블을 재결합하는 것이 중요합니까? 차이점이 뭐야?
질문 : 빠른 데이터로드는 실제로 무엇을합니까? 언제/그게 효과가 있지 않습니까?
질문 : 모든 유형 (x는 표, y는 목록, z는 숫자 등)을 지정하면 성능상의 이점이 있습니까?
질문 : 일부 문서에서는 let..in이 레코드 주위의 구문 설탕이라는 것을 읽었습니다. 중간 값을 모두 사용할 수 있으므로 레코드를 선호하기 시작했습니다. 성능에 미치는 영향은 무엇입니까?
질문 : 숫자 유형간에 차이가 있습니까? Int32.Type 대 Int64.Type?
안녕하세요. 질문이 여전히 유효하면 일부 (아마도 가장 큰) 파일과 코드를 공유 할 수 있습니까? 또한 게시물을 편집하고 코드에서 구현 한 로직을 설명하십시오. 어떤 행동은 나에게 과도한 것처럼 보입니다. 다음과 같이 명확하게 (단계별로) 데이터 변환을 명시하십시오. 1. 빈 행과 유효하지 않은 데이터를 필터링하십시오. 2. 다른 (무엇?) 필터를 적용합니다. 3. 다른 일을하십시오. 등등. 당신의 질문은 아주 도전적 보인다! :) – Eugene