如何将由字典组成的元组列表转换为pandas数据框

3

问题陈述

我有一个字典的元组列表: [(A, B), (A, B),...]. 我���用了 AB 代表这些 "类型" 的字典,因为这些键在这些字典之间都是相同的。

我需要从 AB 中提取一些键来创建一个数据框。

A 中的某些键也出现在 B 中。我想保留 A 中的键。

解决方案:

我能想到几种方法,我很好奇哪种方法更高效。我按照我的猜测将它们列在了下面:

  • 使用列表推导式创建新的字典(或者将 A 扩展为包含部分 B),然后使用 pd.DataFrame.from_records 创建数据框。

  • pd.DataFrame.from_records 有一个排除参数。首先合并较大的字典,然后在构建数据框时排除列。

  • 转置元组的列表(可能使用 zip(*)?),使用 .from_records 创建两个数据框,一个用于A,另一个用于B,然后从每个数据框中删除不必要的列,并将得到的数据框侧面粘合在一起。

  • 将每个字典(行)分别创建为数据框,然后在垂直方向上将它们堆叠在一起(appendconcat 等)。

作为 pandas 的完全新手,很难判断每个操作是什么,何时正在构建视图或执行复制,因此我无法确定哪些操作是昂贵的。

  • 我是否忽略了某种方法?

  • 我的解决方案排列是否正确?

  • 如果将 AB 改为数据框,那么连接它们是否更快?数据框有多少内存开销,是否常见实践将其作为单行数据框?

细节说明:

这里是一些简化的示例数据:

[({"chrom": "chr1", "gStart": 1000, "gEnd": 2000, "other": "drop this"}, 
  {"chrom": "chr1": "pStart": 1500, "pEnd": 2500, "drop": "this"}), 
 ({"chrom": "chr2", "gStart": 8000, "gEnd": 8500, "other": "unimportant"}, 
  {"chrom": "chr2": "pStart": 7500, "pEnd": 9500, "drop": "me"}) ]

我想要的结果应该是以下内容的输出:

我认为,这将是以下行动的结果:

 pd.DataFrame.from_records([ 
  {"chrom": "chr1", "gStart": 1000, "gEnd": 2000, "pStart": 1500, "pEnd": 2500}, 
  {"chrom": "chr2", "gStart": 8000, "gEnd": 8500, "pStart": 7500, "pEnd": 9500}  ] )

我想要的解决方案的伪代码:

如果字典有一个好用的原地select方法,我认为这个方法可以起作用:

A_fields = [...]
B_fields = [...]
A_B_merged = [a.select(A_fields).extend(b.select(B_fields)) for a, b in A_B_not_merged]

A_B_dataframe = pd.DataFrame.from_records(A_B_merged)

请阅读如何创建好的可重现的pandas示例 - MaxU - stand with Ukraine
我提供的示例数据 @MaxU 怎么样? - Alex Lenail
2个回答

1
你需要向下进入两个级别才能处理输入。你最好的朋友是 chain.from_iterable
import itertools as it
pd.DataFrame.from_records(it.chain.from_iterable(l))
Out[21]: 
  chrom    gEnd  gStart    pEnd  pStart
0  chr1  2000.0  1000.0     NaN     NaN
1  chr1     NaN     NaN  2500.0  1500.0
2  chr2  8500.0  8000.0     NaN     NaN
3  chr2     NaN     NaN  9500.0  7500.0

这需要经典且简单的清理:
pd.DataFrame.from_records(it.chain.from_iterable(l)).set_index('chrom').stack().unstack()
Out[22]: 
         gEnd  gStart    pEnd  pStart
chrom                                
chr1   2000.0  1000.0  2500.0  1500.0
chr2   8500.0  8000.0  9500.0  7500.0

嗨@Boud,感谢您的回复!有两个问题:当AB中存在重叠键时,pandas会做什么?您能否在您的答案中更详细地解释一下.set_index('chrom').stack().unstack()的作用是什么? - Alex Lenail
此外,尽管我的示例数据过于简化,但我仍需要删除来自A列和B列的某些列。我应该如何删除它们? - Alex Lenail
我对 .set_index('chrom').stack().unstack() 感到担忧,因为我有许多行将具有 chrom: 'chr1'。我不想按 chrom 索引。尽管如此,我喜欢 chain.from_iterable... @Boud - Alex Lenail

0

使用普通的字典合并,通过Pythonic(Python 3.5+)方式合并起始和结束字典,然后使用from_records构建DataFrame

pd.DataFrame.from_records([{**d[0],**d[1]} for d in k])

  chrom  gEnd  gStart  pEnd  pStart
0  chr1  2000    1000  2500    1500
1  chr2  8500    8000  9500    7500

我真的很喜欢这种语法,但它的性能如何?如果我想从A和B(或您解决方案中的d [0]和d [1])中删除大部分列,我该怎么做? - Alex Lenail
我最终将这个作为我的解决方案的基础。=) - Alex Lenail
能否解释一下 **d[0] 是如何工作的?这是告诉字典扩展操作符只选择每个字典元组的键(第0个元素)的一种方式吗? - matanster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接