【发布时间】:2023-01-29 22:13:57
【问题描述】:
我一直在尝试找到一种方法将具有 4 列的数据集转换为一行。我将举例说明我的意思。
我希望将此数据集转换为...
当我尝试在 Excel 中使用 pivot 函数时,我的问题来了,它不允许我将数据转换为一行。我还在 Excel 中尝试了许多其他功能,但运气不佳。
目前,数据在 Excel 中,在那里操作可能更容易。但是,如果 Excel 根本没有该功能,那么 R 也可以正常工作。感谢您的帮助。
【问题讨论】:
我一直在尝试找到一种方法将具有 4 列的数据集转换为一行。我将举例说明我的意思。
我希望将此数据集转换为...
当我尝试在 Excel 中使用 pivot 函数时,我的问题来了,它不允许我将数据转换为一行。我还在 Excel 中尝试了许多其他功能,但运气不佳。
目前,数据在 Excel 中,在那里操作可能更容易。但是,如果 Excel 根本没有该功能,那么 R 也可以正常工作。感谢您的帮助。
【问题讨论】:
一个技巧是先将数据重塑为长格式,然后在使用 tidyverse 系列的 tidyr 进行几次操作后将数据重塑为宽格式: 我首先将您的示例数据存储在名为“df”的 R 中:
df
ID sit1 sit2 sit3 sit4
1 -1 2 0 0
2 -3 -2 -3 -2
3 -1 2 0 4
4 -1 2 0 0
将 df 转换为长格式,将所有坐柱合并为一个 名为“坐”的单列:
dflong<-pivot_longer(df[,-c(1)],cols = everything(),names_to =
'sit',values_to = 'values')
使 sit 的值独一无二:
dflong$sit<-paste(dflong$sit,rep(c(1:4),each=4),sep = '_')
然后将数据重塑为宽格式,将每个坐值分配到一列中
dfwide<-pivot_wider(dflong,names_from = 'sit',values_from = 'values')
希望这会有所帮助。
【讨论】:
df <- tibble::tribble(
~ID, ~sit1, ~sit2, ~sit3, ~sit4,
1, -1, 2, 0, 0,
2, -3, -2, -3, -2,
3, -1, 2, 0, 4,
4, -1, 2, 0, 0
)
library(tidyr)
col_order <- expand.grid(names(df)[-1], df$ID) |>
unite("Var", c(Var1, Var2))
df |>
pivot_wider(names_from = ID, values_from = starts_with("sit")) |>
dplyr::relocate(col_order$Var)
# A tibble: 1 × 16
sit1_1 sit2_1 sit3_1 sit4_1 sit1_2 sit2_2 sit3_2 sit4_2 sit1_3 sit2_3 sit3_3
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 -1 2 0 0 -3 -2 -3 -2 -1 2 0
# … with 5 more variables: sit4_3 <dbl>, sit1_4 <dbl>, sit2_4 <dbl>, sit3_4 <dbl>,
# sit4_4 <dbl>
【讨论】:
使用最新版本的 Excel 365 中的 Excel 函数应该可以解决这个问题。
但它也可以使用 Windows Excel 2010+ 和 Excel 365(Windows 或 Mac)中提供的 Power Query 来完成
使用 Power Query
Data => Get&Transform => from Table/Range或from within sheet
Home => Advanced Editor
Applied Steps以了解算法
我提供了两种不同的方法来做到这一点。你应该测试看看哪个对你的实际数据更有效
M 代码版本 1
let
Source = Excel.CurrentWorkbook(){[Name="myTable"]}[Content],
colNames = Table.ColumnNames(Source),
//set data types
#"Changed Type" = Table.TransformColumnTypes(Source,
List.Transform(colNames, each {_, Int64.Type})),
x = List.Transform(List.RemoveFirstN(colNames,1),(cn)=>{cn, cn & Text.From(1)}),
//put each row in wide format
tableData = Table.RemoveColumns(#"Changed Type", colNames{0}),
wideList = List.Generate(
()=>[r= tableData{0}, idx=0],
each [idx] < Table.RowCount(tableData),
each [r=tableData{[idx]+1}, idx = [idx]+1],
each Record.RenameFields([r], List.Transform(List.RemoveFirstN(colNames,1), (cn)=>{cn, cn & "_" & Text.From([idx]+1)}))),
wideTable = Table.FromRecords({Record.Combine(wideList)}),
#"Wide Table Typed Columns" = Table.TransformColumnTypes(wideTable, List.Transform(Table.ColumnNames(wideTable), each {_, Int64.Type}))
in
#"Wide Table Typed Columns"
M 代码版本 2
let
Source = Excel.CurrentWorkbook(){[Name="myTable"]}[Content],
//set data types
colNames = Table.ColumnNames(Source),
#"Changed Type" = Table.TransformColumnTypes(Source,
List.Transform(colNames, each {_, Int64.Type})),
//Unpivot to => three columns
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"ID"}, "Attribute", "Value"),
//Group by ID
//then Pivot and rename the columns
#"Grouped Rows" = Table.Group(#"Unpivoted Other Columns", {"ID"}, {
{"pivot", each Table.ToRecords(Table.RemoveColumns(
Table.RenameColumns(
Table.Pivot(_, List.Distinct([Attribute]), "Attribute","Value"),
List.Transform(List.Distinct([Attribute]), (cn)=>{cn, cn & Number.ToText([ID]{0},"_0")})),
"ID"))}
}),
wide = Table.FromRecords({Record.Combine(List.Combine(#"Grouped Rows"[pivot]))}),
//set data types
typedWide = Table.TransformColumnTypes(wide, List.Transform(Table.ColumnNames(wide), each {_, Int64.Type}))
in
typedWide
【讨论】: