抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

我目前在工作中已经几乎不用R做数据处理或者数据清洗了, 因为日常工作的数据整理工作涉及大量的字符串提取/处理工作, 这些用R弄起来很难受. 另外R的错误追踪实在是很吃对代码的熟练度和编写经验, 让我这种只是写写简单脚本, 没什么编程规范意识的人编写和维护R代码简直要命(上间公司尝试过了…), 但是最近有同学要求我使用R语言来完成这类工作(因为他只会R), 于是在艰难抄代码的过程中我发现了一条新的不用R做这种工作的理由…

需要完成的内容无非是对数据框取子集, 然后根据子集的行内容解析生成新的列, 再将解析的几个子集拼接起来. 这些内容我在Pandas做过无数次了… 也因此慢慢掌握了pandas里apply, group, pivot_table, melt这几个函数的使用, 目前完全没有碰到过这几个东西解决不了的处理, 唯一的问题… 就是代码编写的能力不太行, 因此有些东西写出来以后效率实在堪忧…

但是同样的操作在R下那要费了老命了… 毕竟是两种不同的语言, 想在R下找到对等物或者类似物来按照用Pandas的思路处理数据, 是非常困难的一件事, 就连有对等物的apply, 在这次编写中都出现了我无法解决的问题, 导致最后用回了for循环…

要进行的处理, 大概是从数据集data中选取子集sub, 这个sub实际包含两部分内容: AB. 需要进行的处理是逐行进行判断, 如果A部分的内容没有缺失, 则返回A部分, 反之返回B部分, 每一行的返回值形成一个新的数据框.

这个用Pandas很好实现, 对子集apply, 然后编写函数对得到的行判断后, 返回行结果, apply完成后直接就是想要的数据框了. 但是在R下就不是这么回事了, 我最开始是这么弄的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 编写函数用于返回需要的内容
mkSel <- function(rec){
mkA <- rec[['MarkerA']]
mkB <- rec[['MarkerB']]
if (is.na(mkB)) {
row <- c(mkA, rec[['ColA1']], rec[['ColA2']], rec[['ColA3']])
} else {
row <- c(mkB, rec[['ColB1']], rec[['ColB2']], rec[['ColB3']])
}
names(row) <- c('Marker','Tag1', 'Tag2','Tag3')
return(row)
}
# 原代码没有文件记录,下面这个可能会有问题, 印象中用apply出来的只能是列,拼接成数据框, 所以转置
sub[,c('Marker','Tag1', 'Tag2','Tag3')] <- data.frame(t(apply(sub, 1, mkSel, simplify=T)))

这段代码完全是按照用Pandas的处理在弄, 最后也确实能够运行. 但是这里面有个巨大的问题: 向量内元素的数据类型必须是相同的, 我在将收集的数值放到同一个向量中时, 非字符串元素的类型就被自动变成字符串了, 因此虽然能运行, 但是新生成的4列已经全部是字符串了.

为了尝试解决这个问题, 我用list来替代函数内的向量, 有了一个中间版本, 然后我想到第二个问题: t()的转置是把数据当作矩阵来处理的, 因为R的列是一个个向量, 如果不这么做, 转置后一列就有多个数据类型了… 因此我不私心的去网上翻了半天, 抄了一段代码避免使用t(), 有了如下版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 编写函数用于返回需要的内容
mkSel <- function(rec){
mkA <- rec[['MarkerA']]
mkB <- rec[['MarkerB']]
if (is.na(mkB)) {
row <- list(mkA, rec[['ColA1']], rec[['ColA2']], rec[['ColA3']])
} else {
row <- list(mkB, rec[['ColB1']], rec[['ColB2']], rec[['ColB3']])
}
names(row) <- c('Marker','Tag1', 'Tag2','Tag3')
return(row)
}

sub[,c('Marker','Tag1', 'Tag2','Tag3')] <- do.call(rbind.data.frame, apply(sub, 1, mkSel, simplify=T))

但是测试完后我才发现了最大的问题… apply这个函数… 他根本就不能返回数据框, 只能返回矩阵, 矩阵本来就是行列同类型的… 甚至整个函数家族就没有一个是能完成我的需求的, 所以我无论怎么努力, 只要用apply这个目标就是无法实现的.

于是我最后还是用回了质朴的for循环解决了问题… 生成一个空数据框, 规定每一列的类型, 然后读取sub数据框的每一行来生成新数据框, 最后根据编号将两个数据框合并…

所以总结下来, R里的apply在设计的时候就没想我这么去用吧… 只能用基础函数… 通过比较麻烦(需要多写好几行, 同时代码效率和可复用性上似乎不太好)的方式来实现我用Pandas时的做法…

当然平心而论, 我对R的熟练度已经远不如Pandas了, 很多好用的R包我都没有怎么使用过(如dplyr), 所以也许R也能很好的完成这些工作… 只是… 我搜索不到相关的材料?

评论

留下友善的评论吧~