普通行列转换

/*
普通行列转换(2007-11-18于海南三亚)

假设有张学生成绩表(tb)如下:
Name Subject Result
张三 语文  74
张三 数学  83
张三 物理  93
李四 语文  74
李四 数学  84
李四 物理  94
*/

-------------------------------------------------------------------------
/*

想变成
姓名         语文        数学        物理         
---------- ----------- ----------- -----------
李四         74          84          94
张三         74          83          93
*/

create table tb
(
   Name   
varchar(10) ,
   Subject
varchar(10) ,
   Result 
int
)

insert into tb(Name , Subject , Result) values('张三' , '语文' , 74)
insert into tb(Name , Subject , Result) values('张三' , '数学' , 83)
insert into tb(Name , Subject , Result) values('张三' , '物理' , 93)
insert into tb(Name , Subject , Result) values('李四' , '语文' , 74)
insert into tb(Name , Subject , Result) values('李四' , '数学' , 84)
insert into tb(Name , Subject , Result) values('李四' , '物理' , 94)
go

--静态SQL,指subject只有语文、数学、物理这三门课程。
select name 姓名,
 
max(case subject when '语文' then result else 0 end) 语文,
 
max(case subject when '数学' then result else 0 end) 数学,
 
max(case subject when '物理' then result else 0 end) 物理
from tb
group by name
/*
姓名         语文        数学        物理         
---------- ----------- ----------- -----------
李四         74          84          94
张三         74          83          93
*/

--动态SQL,指subject不止语文、数学、物理这三门课程。
declare @sql varchar(8000)
set @sql = 'select Name as ' + '姓名'
select @sql = @sql + ' , max(case Subject when ''' + Subject + ''' then Result else 0 end) [' + Subject + ']'
from (select distinct Subject from tb) as a
set @sql = @sql + ' from tb group by name'
exec(@sql)
/*
姓名         数学        物理        语文         
---------- ----------- ----------- -----------
李四         84          94          74
张三         83          93          74
*/

-------------------------------------------------------------------
/*
加个平均分,总分
姓名         语文        数学        物理        平均分                总分         
---------- ----------- ----------- ----------- -------------------- -----------
李四         74          84          94          84.00                252
张三         74          83          93          83.33                250
*/

--静态SQL,指subject只有语文、数学、物理这三门课程。
select name 姓名,
 
max(case subject when '语文' then result else 0 end) 语文,
 
max(case subject when '数学' then result else 0 end) 数学,
 
max(case subject when '物理' then result else 0 end) 物理,
 
cast(avg(result*1.0) as decimal(18,2)) 平均分,
 
sum(result) 总分
from tb
group by name
/*
姓名         语文        数学        物理        平均分                总分         
---------- ----------- ----------- ----------- -------------------- -----------
李四         74          84          94          84.00                252
张三         74          83          93          83.33                250
*/

--动态SQL,指subject不止语文、数学、物理这三门课程。
declare @sql1 varchar(8000)
set @sql1 = 'select Name as ' + '姓名'
select @sql1 = @sql1 + ' , max(case Subject when ''' + Subject + ''' then Result else 0 end) [' + Subject + ']'
from (select distinct Subject from tb) as a
set @sql1 = @sql1 + ' , cast(avg(result*1.0) as decimal(18,2)) 平均分,sum(result) 总分 from tb group by name'
exec(@sql1)
/*
姓名         数学        物理        语文        平均分                总分         
---------- ----------- ----------- ----------- -------------------- -----------
李四         84          94          74          84.00                252
张三         83          93          74          83.33                250
*/

drop table tb   

---------------------------------------------------------
--
-------------------------------------------------------
/*

如果上述两表互相换一下:即

姓名 语文 数学 物理
张三 74  83  93
李四 74  84  94

想变成
Name       Subject Result     
---------- ------- -----------
李四         语文      74
李四         数学      84
李四         物理      94
张三         语文      74
张三         数学      83
张三         物理      93
*/

create table tb1
(
   姓名
varchar(10) ,
   语文
int ,
   数学
int ,
   物理
int
)

insert into tb1(姓名 , 语文 , 数学 , 物理) values('张三',74,83,93)
insert into tb1(姓名 , 语文 , 数学 , 物理) values('李四',74,84,94)

select * from
(
 
select 姓名 as Name , Subject = '语文' , Result = 语文 from tb1
 
union all
 
select 姓名 as Name , Subject = '数学' , Result = 数学 from tb1
 
union all
 
select 姓名 as Name , Subject = '物理' , Result = 物理 from tb1
) t
order by name , case Subject when '语文' then 1 when '数学' then 2 when '物理' then 3 when '总分' then 4 end

--------------------------------------------------------------------
/*
加个平均分,总分
Name       Subject     Result              
---------- -------    --------------------
李四         语文      74.00
李四         数学      84.00
李四         物理      94.00
李四         平均分    84.00
李四         总分      252.00
张三         语文      74.00
张三         数学      83.00
张三         物理      93.00
张三         平均分    83.33
张三         总分      250.00
*/

select * from
(
 
select 姓名 as Name , Subject = '语文' , Result = 语文 from tb1
 
union all
 
select 姓名 as Name , Subject = '数学' , Result = 数学 from tb1
 
union all
 
select 姓名 as Name , Subject = '物理' , Result = 物理 from tb1
 
union all
 
select 姓名 as Name , Subject = '平均分' , Result = cast((语文 + 数学 + 物理)*1.0/3 as decimal(18,2)) from tb1
 
union all
 
select 姓名 as Name , Subject = '总分' , Result = 语文 + 数学 + 物理 from tb1
) t
order by name , case Subject when '语文' then 1 when '数学' then 2 when '物理' then 3 when '平均分' then 4 when '总分' then 5 end

drop table tb1

<think>我们正在处理用户关于`rownames_to_column`和`column_to_rownames`函数的使用问题。根据用户提供的引用和之前对话历史,我们可以总结如下: 1. 这两个函数来自`tibble`包,因此在使用前需要加载该包(`library(tibble)`)[^2]。 2. `rownames_to_column`用于将数据框的行名转换为一个新的列,而`column_to_rownames`则是将某一列转换为行名[^1]。 3. 用户希望了解如何具体使用这两个函数进行行列转换。 我们将通过以下步骤进行说明: - 安装和加载必要的包 - 创建示例数据框(带行名) - 演示`rownames_to_column`将行名为列 - 演示`column_to_rownames`将列为行名 - 注意事项和常见问题 注意:在R中,数据框(data.frame)和tibble(tbl_df)都可以使用这两个函数,但tibble是tidyverse中的现代数据框,推荐使用。 ### 步骤1: 安装与加载包 如果尚未安装`tibble`包,请先安装。然后加载包: ```r # 安装tibble包(如果未安装) # install.packages("tibble") # 加载包 library(tibble) ``` ### 步骤2: 创建示例数据 创建一个带有行名的数据框: ```r # 创建一个数据框,行名为字母,两列数据 df <- data.frame( Value1 = c(10, 20, 30), Value2 = c(15, 25, 35), row.names = c("A", "B", "C") # 设置行名 ) # 查看数据 print(df) # Value1 Value2 # A 10 15 # B 20 25 # C 30 35 ``` ### 步骤3: 使用`rownames_to_column`将行名转换为列 将行名转换为一个名为"ID"的新列: ```r # 将行名转换为列 df_with_id <- rownames_to_column(df, var = "ID") # 查看转换后的数据 print(df_with_id) # ID Value1 Value2 # 1 A 10 15 # 2 B 20 25 # 3 C 30 35 ``` 注意:参数`var`用于指定新列的名称,如果不指定,默认为"rowname"。 ### 步骤4: 使用`column_to_rownames`将列转换为行名 现在,我们将"ID"列转换回行名: ```r # 将"ID"列转换为行名 df_restored <- column_to_rownames(df_with_id, var = "ID") # 查看恢复后的数据 print(df_restored) # Value1 Value2 # A 10 15 # B 20 25 # C 30 35 ``` 此时,数据框又恢复了最初的行名。 ### 注意事项 1. **包加载问题**:如果遇到函数未找到的错误(如`could not find function "column_to_rownames"`),请确保已正确加载`tibble`包[^2]。 2. **行名唯一性**:在将列转换为行名时,该列的值必须是唯一的,否则会报错。 3. **数据框类型**:`tibble`与传统的`data.frame`在打印和子集选取上有所不同,但这两个函数在两种类型上都能使用。 4. **管道操作**:在`tidyverse`中,我们可以使用管道`%>%`来链调用: ```r library(dplyr) df %>% rownames_to_column("ID") %>% mutate(Value3 = Value1 + Value2) %>% # 添加新列 column_to_rownames("ID") ``` ### 实际应用场景 在生物信息学中,我们经常需要将基因名(作为行名)转换为列,以便进行数据整理(如使用`dplyr`包),然后再转换回行名以满足某些分析包(如`limma`)的要求[^1]。 ### 常见问题解答 **问题1:转换后数据框的行名顺序会改变吗?** 不会,转换操作不会改变行的顺序,只是将行名移动到一个新列,或者将一列的值设置为行名。 **问题2:转换后原始数据会改变吗?** 这些函数不会修改原始数据框,而是返回一个新的数据框。因此,需要将结果赋值给新变量或覆盖原变量。 **问题3:除了`tibble`包,还有其他方法吗?** 是的,基础R中也有类似操作: - 将行名为列:`df$new_col <- rownames(df)` - 将列为行名:`rownames(df) <- df$col; df$col <- NULL` 但使用`tibble`包中的函数更安全(如避免行名重复问题)且易于在管道中使用。 ### 总结 - `rownames_to_column()`:行名→列,参数`var`指定新列名。 - `column_to_rownames()`:列→行名,参数`var`指定要转换的列名。 通过这两个函数,可以方便地在行名和列之间转换,特别适合在数据整理和特定分析需求之间切换。 §§相关问题§§ 1. 在tidyverse中如何避免行名转换时出现重复值? 2. 使用column_to_rownames函数后,如何保存修改后的数据框? 3. 除了tibble包,还有哪些R包提供了类似的行列转换功能?</think>### 在R中使用`rownames_to_column`和`column_to_rownames`进行行列转换 #### 1. **函数基础用法** 这两个函数来自`tibble`包,用于数据框的行名与列数据之间的转换: ```r library(tibble) # 必须加载包[^2] # 创建带行名的示例数据 df <- data.frame( Value = c(1.2, 0.8, 1.5), row.names = c("GeneA", "GeneB", "GeneC") ) # 将行名转换为新列"Gene" df_new <- rownames_to_column(df, var = "Gene") # 将"Gene"列回行名 df_restored <- column_to_rownames(df_new, var = "Gene") ``` #### 2. **详细参数说明** | 函数 | 参数 | 作用 | 示例 | |-----------------------|---------|-------------------------------|--------------------------| | `rownames_to_column()`| `var` | 指定新列名(默认"rowname") | `var = "Gene_ID"` | | `column_to_rownames()`| `var` | 指定要为行名的列名 | `var = "Sample_ID"` | #### 3. **生物信息学应用案例** **基因表达矩阵处理流程:** ```r # 原始数据(行名为基因名) expression_data <- data.frame( Sample1 = rnorm(3), Sample2 = rnorm(3), row.names = c("TP53", "BRCA1", "EGFR") ) # 步骤1: 行名列(便于tidyverse操作) tidy_data <- rownames_to_column(expression_data, "Gene") # 步骤2: 数据处理(示例:过滤低表达基因) filtered_data <- tidy_data %>% filter(Sample1 > 0 & Sample2 > 0) # 步骤3: 回行名格(供DESeq2等包使用) final_data <- column_to_rownames(filtered_data, "Gene") ``` #### 4. **注意事项与常见问题** 1. **包依赖问题**: ```r # 错误处理:函数未找到 if(!require(tibble)) install.packages("tibble") # 引用[2] ``` 2. **行名唯一性检查**: ```r # 确保转换列无重复值 df %>% distinct(Gene, .keep_all = TRUE) %>% # 去重 column_to_rownames("Gene") ``` 3. **数据类型保留**: ```r # 转换后验证数据类型 str(column_to_rownames(df, "Gene")) ``` 4. **管道操作最佳实践**: ```r mtcars %>% rownames_to_column("Car") %>% filter(mpg > 20) %>% mutate(CarType = ifelse(grepl("Toyota", Car), "Japanese", "Other")) %>% column_to_rownames("Car") ``` #### 5. **与传统方法的对比** | 方法 | 优点 | 缺点 | |---------------------|---------------------------|---------------------------| | `rownames_to_column`| 保留行名数据,兼容tidyverse | 需额外加载包 | | 基础R方法 | 无需额外包 | 代码冗长,易出错 | ```r # 基础R实现相同功能 df$Gene <- rownames(df) # 行名列 rownames(df) <- df$Gene # 列行名 df$Gene <- NULL # 需手动删除原列 ``` > **关键提示**:在生物信息分析中,建议仅在需要行名的第三方包(如DESeq2、limma)中使用`column_to_rownames`,在数据清洗阶段保持标识列为普通数据列[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值