将值列表添加到行,然后将数据框转换为长格式
Posted
技术标签:
【中文标题】将值列表添加到行,然后将数据框转换为长格式【英文标题】:Adding list of values to rows, turning the dataframe into long format afterwards 【发布时间】:2015-07-12 08:48:33 【问题描述】:我有一个数据框,其中索引是基因组位置,值是 p 值:
import pandas as pd
from StringIO import StringIO
from collections import defaultdict
data = """Pos MedialIIvsD LateralIIvsD MedialP02IIvsD MedialP09IIvsD
chr1_-_12200 0.557431 0.066554 0.738343 0.029935
chr1_-_12600 0.737887 0.069167 0.829568 0.409495
chr1_-_48400 0.349833 0.600912 0.964103 0.765195
chr1_-_172800 0.729035 0.035198 0.866111 0.385711"""
df = pd.read_csv(StringIO(data), sep='\s+', index_col=False,
header=False)
此外,我还有一个将不同基因组位置映射到基因的字典:
pos_to_gene = defaultdict(list, "chr1_-_12200": ["GENE1"],
"chr1_-_12600": ["GENE1", "GENE2"],
"chr1_-_172800": ["GENE3"])
我想要实现的是在此数据框中添加 Gene
作为列。这对我来说并不简单,因为一个基因组位置可能有多个基因:
pd.Series(df.index.values).apply(lambda pos: pos_to_gene[pos])
0 [GENE1]
1 [GENE1, GENE2]
2 []
3 [GENE3]
dtype: object
如何实现这样的长格式输出数据帧?
Gene Pos MedialIIvsD LateralIIvsD MedialP02IIvsD MedialP09IIvsD
GENE1 chr1_-_12200 0.557431 0.066554 0.738343 0.029935
GENE1 chr1_-_12600 0.737887 0.069167 0.829568 0.409495
GENE2 chr1_-_12600 0.737887 0.069167 0.829568 0.409495
NaN chr1_-_48400 0.349833 0.600912 0.964103 0.765195
GENE3 chr1_-_172800 0.729035 0.035198 0.866111 0.385711
【问题讨论】:
我迫切需要一个更好的标题。不胜感激。 这可能会有所帮助:***.com/questions/26068021/… 谢谢!将不得不调查,希望它不是完全重复。 它们 90% 相似,但在我的情况下还需要几行。谢谢! 【参考方案1】:应用我在answer here 中学到的知识:
df.insert(0, "Gene", df.Pos.apply(lambda pos: pos_to_gene[pos]))
def expand(row):
genes = row['Gene']
s = pd.Series(row['Pos'], index=list(set(genes)))
return s
sdf = df.apply(expand, axis=1).stack()
返回
0 GENE1 chr1_-_12200
1 GENE1 chr1_-_12600
GENE2 chr1_-_12600
3 GENE3 chr1_-_172800
dtype: object
非常接近;缺少的只是其余的数据。
现在剩下的就是合并堆叠数据框 (sdf
) 和原始数据框 (df
)。
sdf = sdf.to_frame().reset_index(level=1, drop=False)
sdf.columns = ["Gene", "Pos"]
pd.merge(sdf, df, left_on = 'Pos', right_on = 'Pos')
就是这样!
Gene Pos MedialIIvsD LateralIIvsD MedialP02IIvsD \
0 GENE1 chr1_-_12200 0.557431 0.066554 0.738343
1 GENE1 chr1_-_12600 0.737887 0.069167 0.829568
2 GENE2 chr1_-_12600 0.737887 0.069167 0.829568
3 GENE3 chr1_-_172800 0.729035 0.035198 0.866111
MedialP09IIvsD
0 0.029935
1 0.409495
2 0.409495
3 0.385711
也许有更聪明的方法来做到这一点。
【讨论】:
【参考方案2】:这里有一个技巧可以使用 pd.Series(1, index=...) 并让 pandas 对齐:
In [11]: s = df["Pos"].apply(lambda x: pd.Series(1, pos_to_gene[x])).stack(0)
In [12]: s
Out[12]:
0 GENE1 1
1 GENE1 1
GENE2 1
3 GENE3 1
dtype: float64
您可以重置索引,然后简单地加入:
In [13]: s.index.names = [None, "Gene"]
In [14]: gene = s.reset_index("Gene")[["Gene"]]
In [15]: gene
Out[15]:
Gene
0 GENE1
1 GENE1
1 GENE2
3 GENE3
In [16]: gene.join(df)
Out[16]:
Gene Pos MedialIIvsD LateralIIvsD MedialP02IIvsD MedialP09IIvsD
0 GENE1 chr1_-_12200 0.557431 0.066554 0.738343 0.029935
1 GENE1 chr1_-_12600 0.737887 0.069167 0.829568 0.409495
1 GENE2 chr1_-_12600 0.737887 0.069167 0.829568 0.409495
3 GENE3 chr1_-_172800 0.729035 0.035198 0.866111 0.385711
如果您想包含 NaN 行(不在您的答案中),那么外部联接:
In [17]: gene.join(df, how="outer")
Out[17]:
Gene Pos MedialIIvsD LateralIIvsD MedialP02IIvsD MedialP09IIvsD
0 GENE1 chr1_-_12200 0.557431 0.066554 0.738343 0.029935
1 GENE1 chr1_-_12600 0.737887 0.069167 0.829568 0.409495
1 GENE2 chr1_-_12600 0.737887 0.069167 0.829568 0.409495
2 NaN chr1_-_48400 0.349833 0.600912 0.964103 0.765195
3 GENE3 chr1_-_172800 0.729035 0.035198 0.866111 0.385711
作为替代方案,您可以在纯 python 中创建 gene
(而不是使用 apply):
inds, gens = [], []
for i, p in df["Pos"].iteritems():
for g in pos_to_gene[p]:
inds.append(i)
gens.append(g)
gene = pd.Series(gens, inds)
【讨论】:
注意:对 Pos 列使用分类也可能会有所帮助,如果有很多重复,可能可以节省一些工作... 谢谢,我的版本非常慢。将报告这是如何工作的。 没有重复,但会记住另一次。顺便说一句,感谢您的 git 书。 @TheUnfunCat 哦,你是读者! :p 我必须发布一些最近的编辑,谢谢你提醒我!! @您应该尝试将其添加到 goodreads.com,以便人们可以传播福音。将给出至少 4/5 的完成版本。让草稿版本像 (braveclojure.com) 一样开放可能是获得大量良好反馈/口碑的好方法。以上是关于将值列表添加到行,然后将数据框转换为长格式的主要内容,如果未能解决你的问题,请参考以下文章