【问题标题】:Efficiently concatanate a large number of columns高效连接大量列
【发布时间】:2015-04-16 08:46:06
【问题描述】:

我试图在一个字符串中连接大量包含整数的列。

基本上,从:

df = pd.DataFrame({'id':[1,2,3,4],'a':[0,1,2,3], 'b':[4,5,6,7], 'c':[8,9,0,1]})

获得:

id join
0   1  481
1   2  592
2   3  603
3   4  714

我找到了几种方法来做到这一点(herehere):

方法一:

conc['glued']=''
i=1
while i < len(df.columns):
        conc['glued'] = conc['glued'] + df[df.columns[i]].values.astype(str)
        i=i+1

此方法有效,但有点长(在我的 18,000 行 x 40,000 列的“测试”案例中需要 45 分钟)。我担心列上的循环,因为这个程序应该在最后应用到 600.000 列的表上,我担心它会太长。

方法2a

conc['join']=[''.join(row) for row in df[df.columns[1:]].values.astype(str)]

方法2b

conc['apply'] = df[df.columns[1:]].apply(lambda x: ''.join(x.astype(str)), axis=1)

这两种方法的效率都是前一种方法的 10 倍,对行进行迭代非常好,并且在我的“调试”表 df 上完美运行。但是,当我将它应用于 18k x 40k 的“测试”表时,它会导致MemoryError:(在读取相应的 csv 文件后,我占用了 32GB RAM 的 60%)。 我可以在不超出内存的情况下复制我的 DataFrame,但奇怪的是,应用此方法会使代码崩溃。

您知道我可以如何修复和改进此代码以使用有效的基于行的迭代吗?谢谢!


附录: 这是我在测试用例中使用的代码:

geno_reader = pd.read_csv(genotype_file,header=0,compression='gzip', usecols=geno_columns_names)
fimpute_geno = pd.DataFrame({'SampID': geno_reader['SampID']})

我应该使用 chunksize 选项来读取这个文件,但我还没有真正理解如何在阅读后使用它。

方法一:

fimpute_geno['Calls'] = ''
for i in range(1,len(geno_reader.columns)):
    fimpute_geno['Calls'] = fimpute_geno['Calls']\
                      + geno_reader[geno_reader.columns[i]].values.astype(int).astype(str)

这项工作需要 45 分钟。 有一些非常恶心的代码,比如.astype(int).astype(str)。我不知道为什么 Python 不能识别我的整数并将它们视为浮点数。

方法二:

fimpute_geno['Calls'] = geno_reader[geno_reader.columns[1:]]\
                    .apply(lambda x: ''.join(x.astype(int).astype(str)), axis=1)

这导致MemoryError:

【问题讨论】:

  • 你在做一些奇怪的事情:fimpute_geno = pd.DataFrame({'SampID': geno_reader['SampID']}) 为什么要创建一个新的df?你能不能只做fimpute_geno = geno_reader['SampID']?或者你需要一份副本吗? dtype 是浮点数的原因可能是因为您缺少不能表示为 int 的数据 NaN,您需要决定是替换这些值还是删除行,以及您要实现什么,看起来就像您正在尝试构建数据的字符串表示形式
  • 我不使用fimpute_geno = geno_reader['SampID'],因为这只会给我一个系列,或者我需要一个数据框来放置其他信息。我也怀疑有一些 NaN,但似乎没有。

标签: python-3.x pandas dataframe concatenation large-data


【解决方案1】:

这里有一些东西可以尝试。不过,这将要求您将列转换为字符串。您的示例框架

    b   c   id
0   4   8   1
1   5   9   2
2   6   0   3
3   7   1   4

然后

#you could also do this conc[['b','c','id']] for the next two lines  
conc.ix[:,'b':'id'] = conc.ix[:,'b':'id'].astype('str')  
conc['join'] = np.sum(conc.ix[:,'b':'id'],axis=1)

愿意

    a   b   c   id  join
0   0   4   8   1   481
1   1   5   9   2   592
2   2   6   0   3   603
3   3   7   1   4   714

【讨论】:

  • 你的提议让我明白了一些事情:它不是用时间连接事物,而是将它转换成字符串。当我执行geno_test.ix[:,geno_test.columns[1:]] = geno_test.ix[:,geno_test.columns[1:]].astype('str')(有限的 20 行 x 40,000 列表)时,需要十几分钟才能完成。然后,当我做fimpute_geno['Calls'] = np.sum(geno_test.ix[:,geno_test.columns[1:]],axis=1) 时,它是准瞬时的。
  • 是的,有很多列要转换。我猜当 dtypes 改变时会有很多复制。也许您应该修改您的问题或发布有关数据类型部分的新问题
猜你喜欢
  • 1970-01-01
  • 2013-10-21
  • 2017-02-23
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-25
  • 1970-01-01
相关资源
最近更新 更多