使用 Python(或 Power Query)将不同行中的数据转置到同一列,但每隔一段时间

Transpose data from different rows to the same column, but at a regular interval, using Python (or Power Query)

提问人:Phil 提问时间:11/13/2023 最后编辑:Phil 更新时间:11/14/2023 访问量:92

问:

所以,我有一个.xlsx数据集,我称之为“源”数据集。 “源”数据集有数百行,其中包含有关每个物种昆虫数量的信息。 数据集每列的标题都具有每个物种的名称。 我需要将此数据转置到另一个数据集的同一列中,也是一个 .xlsx 文件,我称之为“命运”数据集。

我需要创建一个循环来执行以下操作:

  1. 从单元格“A2”开始,遍历“源”数据集每行的列“A”,并验证是否存在数据。
  2. 如果单元格“A2”中有数据,则将整个信息从单元格“B2”复制到单元格“E2”。
  3. 将复制的数据转置到“命运”数据集的列“C”中,从单元格“C2”开始
  4. 然后,在下一次迭代中,验证源数据集的单元格“A3”中是否有数据,并将整个信息从单元格“B3”复制到单元格“E3”
  5. 然后将复制的数据转置到“命运”数据集的“C”列,但这次从单元格“C2”下方的 7 个单元格开始,即在单元格“C8”处转置。
  6. 在下一次迭代中,始终在上次转置数据下方 7 个单元格处转置来自“源”数据集的数据。

我知道这有点令人困惑,但应该通过下面的示例来澄清:

“源”数据集如下所示:

Point|Spongillidae|Olindiidae|Hydridae|Oceaniidae|
:------|---------:|---------:|-------:|---------:|
 MK1   |3         |          |1       |5         |
 RT2   |2         |7         |        |          |
 GT3   |10        |1         |6       |15        |

当前的“命运”数据集目前如下所示:

Point|  Species   |Value |
:----|:----------:|-----:|
 MK1 |Spongillidae|      |
 MK1 |Olindiidae  |      |
 MK1 |Hydridae    |      |
 MK1 |Oceaniidae  |      |
 MK1 |Colletor    |TG    |
 MK1 |Habitat     |Edge  |
 RT2 |Spongillidae|      |
 RT2 |Olindiidae  |      |
 RT2 |Hydridae    |      |
 RT2 |Oceaniidae  |      |
 RT2 |Colletor    |DG    |
 RT2 |Habitat     |Riffle|
 GT3 |Spongillidae|      |
 GT3 |Olindiidae  |      |
 GT3 |Hydridae    |      |
 GT3 |Oceaniidae  |      |
 GT3 |Colletor    |JB    |
 GT3 |Habitat     |Riffle|

最后,“命运”数据集应如下所示:

Point|  Species   |Value |
:----|:----------:|-----:|
 MK1 |Spongillidae|3     |
 MK1 |Olindiidae  |      |
 MK1 |Hydridae    |1     |
 MK1 |Oceaniidae  |5     |
 MK1 |Colletor    |TG    |
 MK1 |Habitat     |Edge  |
 RT2 |Spongillidae|2     |
 RT2 |Olindiidae  |7     |
 RT2 |Hydridae    |      |
 RT2 |Oceaniidae  |      |
 RT2 |Colletor    |DG    |
 RT2 |Habitat     |Riffle|
 GT3 |Spongillidae|10    |
 GT3 |Olindiidae  |1     |
 GT3 |Hydridae    |6     |
 GT3 |Oceaniidae  |15    |
 GT3 |Colletor    |JB    |
 GT3 |Habitat     |Riffle|

我希望有人能帮我找到解决这个问题的方法。

Python Excel PowerQuery 转置

评论

0赞 Phil 11/13/2023
我想将上面的数据集呈现为表格,但“Stackoverflow”将我的表格视为代码,并迫使我用四个空格标识每行。所以,我很抱歉。
0赞 Ron Rosenfeld 11/13/2023
这可以使用Power Query轻松完成。这是一个选项还是您必须使用 Python?
0赞 Phil 11/14/2023
不,Power Query也很好用。谢谢
0赞 Ron Rosenfeld 11/14/2023
请参阅下面的回答。

答:

0赞 arigo 11/13/2023 #1

请确保您的初始数据从 Sheet1 的左上角开始 (A1=“Point”)。

在Excel中创建一个宏并将其命名为Sub change_format(),并将以下代码粘贴在“Sub change_format()”和“End sub”之间。然后运行它,您将在 Sheet2 中获得结果。确保以 .xlsm 格式保存您的文件!!

i = 1 'First row of Sheet1 for reading
r = 2 'First row of Sheet2 for writing
   
'Find number of Points

While Sheet1.Cells(i, 1) <> ""
    
    i = i + 1

Wend

pnt = i - 2

For p = 1 To pnt 'Points
    For s = 2 To 7 'Species
                 
    cur_type = Sheet1.Cells(p + 1, 1) 'Current type
    cur_spc = Sheet1.Cells(1, s)      'Current species
    cur_val = Sheet1.Cells(p + 1, s)  'Current value
    
    Sheet2.Cells(1, 1) = "Point"
    Sheet2.Cells(1, 2) = "Species"
    Sheet2.Cells(1, 3) = "Value"

    Sheet2.Cells(r, 1) = cur_type
    Sheet2.Cells(r, 2) = cur_spc
    Sheet2.Cells(r, 3) = cur_val
    r = r + 1
    
    Next s
    
Next p
1赞 Ron Rosenfeld 11/13/2023 #2

这也可以使用 Windows Excel 2010+ 和 Microsoft 365(Windows 或 Mac)中提供的 Power Query 完成

使用 Power Query

  • 选择数据表中的某个单元格
  • Data => Get&Transform => from Table/Range
  • 当 PQ 编辑器打开时:Home => Advanced Editor
  • 记下第 2 行中的表
  • 粘贴下面的 M 代码来代替您看到的内容
  • 将第 2 行中的表名称改回最初生成的名称。
  • 阅读评论并探索以了解算法Applied Steps

来源与命运
enter image description here

M代码

let

//Read in Source Table
//  Change depending on your actual data source
    Source = Excel.CurrentWorkbook(){[Name="Source"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(Source,
        {{"Point", type text}} & List.Transform(List.RemoveFirstN(Table.ColumnNames(Source),1), each {_, Int64.Type})), 

//Unpivot to produce a three column table
    #"Unpivot Source" = Table.UnpivotOtherColumns(#"Changed Type",{"Point"},"Species","Value"),

//Read in Destiny Table
//  Change depending on your actual data source
    Source2 = Excel.CurrentWorkbook(){[Name="Destiny"]}[Content],

//Add Index Column for Sorting
    #"Added Index" = Table.AddIndexColumn(Source2, "Index", 0, 1, Int64.Type),
    #"Destiny Typed" = Table.TransformColumnTypes(#"Added Index",{
        {"Point", type text}, {"Species", type text},{"Value", type any}}),

//Join the two tables
    joined = Table.NestedJoin(#"Destiny Typed",
        {"Point","Species"},#"Unpivot Source",{"Point","Species"},"Join",JoinKind.FullOuter),

//Replace the null Values
    #"Replace null Values" = Table.ReplaceValue(
        joined,
        each [Value],
        each if [Value] = null then [Join][Value]{0} else [Value],
        Replacer.ReplaceValue,
        {"Value"}
    ),
    #"Removed Columns" = Table.RemoveColumns(#"Replace null Values",{"Join"}),
    #"Sorted Rows" = Table.Sort(#"Removed Columns",{{"Index", Order.Ascending}}),
    #"Removed Columns1" = Table.RemoveColumns(#"Sorted Rows",{"Index"})
in
    #"Removed Columns1"

结果
enter image description here

注意:实际上,您可以从一个包含每个ColletorHabitat 的源表开始,然后生成整个 Destiny 表。

例如,如果您的表如下所示:Source
enter image description here

然后,一个简单的表格将生成:UnPivotDestiny

et

//change next line to reflect actual data source
    Source = Excel.CurrentWorkbook(){[Name="Source14"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(Source,
        {{"Point", type text}, {"Colletor", type text}, {"Habitat", type text}}
        & List.Transform(List.RemoveFirstN(Table.ColumnNames(Source),3), each {_, Int64.Type})),

//Unpivot all except the Point Column
    #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Point"}, "Attribute", "Value")
in
    #"Unpivoted Other Columns"

生产=>
enter image description here

如果这是可行的,可以很容易地修改代码以包含“空白”条目以及所需的排序顺序。