我有一个大型 Dask DataFrame,看起来像这样:
铬 | POS | 身份证 | 参考 | ALT | 后果 | Ensembl_geneid | Ensembl_蛋白质ID | Ensembl_transcriptid | 等等 |
---|---|---|---|---|---|---|---|---|---|
1 | 10000 | 1-10000-A-C | A | C | con11,con12,con13 | 基因11,.,基因13 | prot11,.,prot13 | tra11,.,tra13 | |
1 | 11000 | 1-11000-A-G | A | G | con21 | 基因21 | prot21 | tra21 | |
2 | 20000 | 2-20000-T-C | T | C | .,.,.,.,. | .,.,.,.,. | .,.,.,.,. | .,.,.,.,. | |
等等 |
所有列均已使用 Dask DataFrame
read_csv(dtypes_mapping)
有意读取为字符串。实际数据基本上是使用 VEP 工具生成的变异注释数据,总共有几百万行和大约 90-100 列(如果有帮助的话)。
每个变体(即 CHROM、POS、ID、REF、ALT)都有一个或多个逗号分隔的值,对应于不同的效果。 “点”是该工具用来表示缺失值的字符串,我稍后会将其替换为正确的
NaN
值。
可能存在部分或完全缺失,但对于每个变体,每个逗号分隔的字符串列中始终有相同数量的位置值(它们是为了匹配)。例如,
我想应用 Dask
Series.str.split(pat=delim, n=-1, expand=False)
和 Dask DataFrame.explode(column=col_list)
方法将数据转换为长格式,同时保持位置值匹配,如下所示:
铬 | POS | 身份证 | 参考 | ALT | 后果 | Ensembl_geneid | Ensembl_蛋白质ID | Ensembl_transcriptid | 等等 |
---|---|---|---|---|---|---|---|---|---|
1 | 10000 | 1-10000-A-C | A | C | con11 | 基因11 | prot11 | tra11 | |
1 | 10000 | 1-10000-A-C | A | C | con12 | . | . | . | |
1 | 10000 | 1-10000-A-C | A | C | con13 | 基因13 | prot13 | tra13 | |
1 | 11000 | 1-11000-A-G | A | G | con21 | 基因21 | prot21 | tra21 | |
2 | 20000 | 2-20000-T-C | T | C | . | . | . | . | |
2 | 20000 | 2-20000-T-C | T | C | . | . | . | . | |
2 | 20000 | 2-20000-T-C | T | C | . | . | . | . | |
2 | 20000 | 2-20000-T-C | T | C | . | . | . | . | |
2 | 20000 | 2-20000-T-C | T | C | . | . | . | . | |
等等 |
当我使用测试样本在 Pandas 中尝试整个过程时,我可以看到使用
.iloc[]
和 type()
,在 Pandas Series.str.split()
之后,Pandas DataFrame 将各个值识别为 list[str]
。这样就可以让 Pandas DataFrame.explode()
按预期工作。
但是,我无法在 Dask 中实现同样的功能。 Dask DataFrame 似乎将 Dask
Series.str.split()
之后的各个值视为 str
而不是 list[str]
("['con11', 'con12', 'con13']"
而不是 ['con11', 'con12', 'con13']
)。这导致 Dask DataFrame.explode()
基本上什么都不做。
这就是我一直提到的,但我不确定接受的解决方案是否适用于我的情况:Dask dataframe - 根据分隔符将列拆分为多行
我无法判断我是否遗漏了一些非常明显的东西,或者这是否是 Dask 设计的限制。任何调试帮助将不胜感激!
编辑:对延迟表示歉意@GuillaumeEB,我在上周左右一直无法回到这个特定问题。这是一个基于上面示例的小型再现器:
### python = 3.12.1 (conda-forge)
### numpy = 1.26.3 (conda-forge)
### pandas = 2.1.4 (conda-forge)
### dask = 2023.12.1 (conda-forge)
import pandas as pd
from dask import dataframe as ddf
reqd_cols = ["Consequence", "Ensembl_geneid", "Ensembl_proteinid", "Ensembl_transcriptid"]
### Pandas implementation start, works as intended
df = pd.DataFrame({
"CHROM": [1, 1, 2],
"POS": [10000, 11000, 20000],
"ID": ["1-10000-A-C", "1-11000-A-G", "2-20000-T-C"],
"REF": ["A", "A", "T"],
"ALT": ["C", "G", "C"],
"Consequence": ["con11,con12,con13", "con21", ".,.,.,.,."],
"Ensembl_geneid": ["gene11,.,gene13", "gene21", ".,.,.,.,."],
"Ensembl_proteinid": ["prot11,.,prot13", "prot21", ".,.,.,.,."],
"Ensembl_transcriptid": ["tra11,.,tra13", "tra21", ".,.,.,.,."]
})
for col in reqd_cols:
df[col] = df[col].str.split(pat=",", expand=False)
df = df.explode(column=reqd_cols, ignore_index=True)
print(df.info(verbose=True))
print(df.head())
### Pandas implementation end
### Dask implementation start, does not work
df = ddf.from_pandas(
data=pd.DataFrame({
"CHROM": [1, 1, 2],
"POS": [10000, 11000, 20000],
"ID": ["1-10000-A-C", "1-11000-A-G", "2-20000-T-C"],
"REF": ["A", "A", "T"],
"ALT": ["C", "G", "C"],
"Consequence": ["con11,con12,con13", "con21", ".,.,.,.,."],
"Ensembl_geneid": ["gene11,.,gene13", "gene21", ".,.,.,.,."],
"Ensembl_proteinid": ["prot11,.,prot13", "prot21", ".,.,.,.,."],
"Ensembl_transcriptid": ["tra11,.,tra13", "tra21", ".,.,.,.,."]
}),
npartitions=1
)
for col in reqd_cols:
df[col] = df[col].str.split(pat=",", n=-1, expand=False)
df = df.explode(column=reqd_cols)
print(df.info(verbose=True))
print(df.head())
### Dask implementation end
如果安装了 pandas>=2 和 pyarrow>=12,Dask DataFrame 将使用对象数据类型自动将文本数据转换为 string[pyarrow]。
为了避免这种情况,您可以在创建 Dask Dataframe 之前停用此功能,只需添加:
import dask
dask.config.set({"dataframe.convert-string": False})
在创建你的之前,它解决了问题。