Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 确保特定列是数据帧中的最后一列(或第一列)的最快方法是什么_Python_Pandas - Fatal编程技术网

Python 确保特定列是数据帧中的最后一列(或第一列)的最快方法是什么

Python 确保特定列是数据帧中的最后一列(或第一列)的最快方法是什么,python,pandas,Python,Pandas,给定df df = pd.DataFrame(np.arange(8).reshape(2, 4), columns=list('abcd')) 假设我需要列'b'位于末尾。我可以做到: df[['a', 'c', 'd', 'b']] 但是,确保给定列位于末尾的最有效方法是什么 这就是我一直在做的。其他人会怎么做 def put_me_last(df, column): return pd.concat([df.drop(column, axis=1), df[column]]

给定
df

df = pd.DataFrame(np.arange(8).reshape(2, 4), columns=list('abcd'))

假设我需要列
'b'
位于末尾。我可以做到:

df[['a', 'c', 'd', 'b']]

但是,确保给定列位于末尾的最有效方法是什么

这就是我一直在做的。其他人会怎么做

def put_me_last(df, column):
    return pd.concat([df.drop(column, axis=1), df[column]], axis=1)

put_me_last(df, 'b')


计时结果 结论 mfripp是赢家。似乎
reindex\u轴
[]
具有更大的效率增益。这真是个好消息

代码

from string import lowercase

df_small = pd.DataFrame(np.arange(8).reshape(2, 4), columns=list('abcd'))
df_large = pd.DataFrame(np.arange(1000000).reshape(10000, 100),
                        columns=pd.MultiIndex.from_product([list(lowercase[:-1]), ['One', 'Two', 'Three', 'Four']]))


def pir1(df, column):
    return pd.concat([df.drop(column, axis=1), df[column]], axis=1)

def pir2(df, column):
    if df.columns[-1] == column:
        return df
    else:
        pos = df.columns.values.__eq__('b').argmax()
        return df[np.roll(df.columns, len(df.columns) - 1 - pos)]

def pir3(df, column):
    if df.columns[-1] == column:
        return df
    else:
        pos = df.columns.values.__eq__('b').argmax()
        cols = df.columns.values
        np.concatenate([cols[:pos], cols[1+pos:], cols[[pos]]])
        return df[np.concatenate([cols[:pos], cols[1+pos:], cols[[pos]]])]

def pir4(df, column):
    if df.columns[-1] == column:
        return df
    else:
        return df[np.roll(df.columns.drop(column).insert(0, column), -1)]

def carsten1(df, column):
    cols = list(df)
    if cols[-1] == column:
        return df
    else:
        return pd.concat([df.drop(column, axis=1), df[column]], axis=1)

def carsten2(df, column):
    cols = list(df)
    if cols[-1] == column:
        return df
    else:
        idx = cols.index(column)
        new_cols = cols[:idx] + cols[idx + 1:] + [column]
        return df[new_cols]

def mfripp1(df, column):
    new_cols = [c for c in df.columns if c != column] + [column]
    return df[new_cols]

def mfripp2(df, column):
    new_cols = [c for c in df.columns if c != column] + [column]
    return df.reindex_axis(new_cols, axis='columns', copy=False)

def ptrj1(df, column):
    return df.reindex(columns=df.columns.drop(column).append(pd.Index([column])))

def shivsn1(df, column):
    column_list=list(df)
    column_list.remove(column)
    column_list.append(column)
    return df[column_list]

def merlin1(df, column):
    return df[df.columns.drop(["b"]).insert(99999, 'b')]


list_of_funcs = [pir1, pir2, pir3, pir4, carsten1, carsten2, mfripp1, mfripp2, ptrj1, shivsn1]

def test_pml(df, pml):
    for c in df.columns:
        pml(df, c)

summary = pd.DataFrame([], [f.__name__ for f in list_of_funcs], ['Small', 'Large'])

for f in list_of_funcs:
    summary.at[f.__name__, 'Small'] = timeit(lambda: test_pml(df_small, f), number=100)
    summary.at[f.__name__, 'Large'] = timeit(lambda: test_pml(df_large, f), number=10)
首先(而且,根据您的用例,也是最有效的)优化是首先确保您不必重新排列数据集。如果您想要成为最后一列的列已经就位,那么您可以不更改地返回df。试试这个:

def put_me_last2(df, column):
    if list(df)[-1] == column:
        return df
    else: return pd.concat([df.drop(column, axis=1), df[column]], axis=1)
df.reindex(columns=df.columns.drop(col).append(pd.Index([col])))
我试过用800万个条目而不是你例子中的8个条目,当我要求列
b
时,速度与上一列差不多,当我希望最后一列是
d
时,速度快了300倍(500us vs 150ms)(即无需重新排序的情况)

如果你有很多列,或者通常想重新排列列,这对你没有帮助,但也没有坏处

更新:

我发现了一种更快的方法:不要删除并重新添加一列,而是使用
df[cols]
和想要的列列表。给我大约40%的加速(90毫秒对150毫秒,有800万个条目)


我将重新排列列列表,而不是删除并追加其中一列:

import pandas as pd
import numpy as np

df = pd.DataFrame(np.arange(8).reshape(2, 4), columns=list('abcd'))

def put_me_last(df, column):
    return pd.concat([df.drop(column, axis=1), df[column]], axis=1)

def put_me_last_fast(df, column):
    new_cols = [c for c in df.columns if c != column] + [column]
    return df[new_cols]

def put_me_last_faster(df, column):
    new_cols = [c for c in df.columns if c != column] + [column]
    return df.reindex_axis(new_cols, axis='columns', copy=False)
计时(在iPython中):

注意:您可以使用下面的行定义新的_cols,但它比上面使用的慢80倍(2µs vs 160µs)

另请注意:如果您经常尝试将列移动到已存在的末尾,则可以通过添加此项将这些情况的时间缩短到1µs以下,如@Carsten所述:

if df.columns[-1] == column:
    return df
这个怎么样:

def put_me_last2(df, column):
    if list(df)[-1] == column:
        return df
    else: return pd.concat([df.drop(column, axis=1), df[column]], axis=1)
df.reindex(columns=df.columns.drop(col).append(pd.Index([col])))
.append([col])
不起作用-可能是个bug。编辑:
.append(pd.Index([col])
可能是append中最安全的选项。)

对测试的评论:如果您计划使用
timeit
进行测试,请尝试在大型df(如1e4行或更多行)上运行它,并且可能使用
-n1-r1
来防止缓存。

从以下内容开始:

 df.columns
 Index([u'a', u'b', u'c', u'd'], dtype='object')
不要这样做,看起来像个虫子。

 df.columns.drop(["b"]).insert(-1, 'b')
 Index([u'a', u'c', u'b', u'd'], dtype='object')

 df.columns.drop(["b"]).insert(-1, 'x')
 Index([u'a', u'c', u'x', u'd'], dtype='object')
围绕以下方面工作

 df.columns.drop(["b"]).insert(99999, 'b')
 Index([u'a', u'c', u'd', u'b'], dtype='object')

但这并不是最快的:

def put_me_last(df,column):
    column_list=list(df)
    column_list.remove(column)
    column_list.append(column)
    return df[column_list]  



%timeit put_me_last(df,'b')
1000 loops, best of 3: 391 µs per loop

如果df.columns[-1],我会将其编辑为
==列:
。但是,是的,这是一个很好的提示。两种方法的工作方式都相同。其中一种可能会快几微秒。如果您进行测试,请将结果添加到我的答案或您的问题中,我会感兴趣的。我添加了一个额外的方法,可以提高40%的速度。请尝试将您的备选方案与模块进行比较。@mhawke我计划好了吗。这就是我将如何决定答案。到目前为止,您的两个备选方案中哪一个更快?我正在进行测试。我必须随机化列顺序,并在不同大小的数据集上测试许多试验。今晚我将有一个。@mhawke到目前为止的唯一答案只有在列已经是最后一个的情况下才有好处。在随机化设置中,它将获得这种好处1/len(columns)。根据列的数量,好处可能不会超过检查的成本。无论如何,我将构建一个适当的测试。IMO,这不是一个bug,它是Python的
list.insert()
方法的标准行为。尝试以下方法:
df.columns.drop('b')。insert(len(df.columns)-1,'b'))
@Merlin:这一点很好。它的行为是经过设计的,但如果你希望在索引末尾插入一个项,那就令人惊讶了。令人恼火的是,df.index.insert()的工作方式类似于list.insert(),但df.index.append()的工作方式不同于list.append()。这意味着没有完全自然的方式将一项添加到索引末尾(必须使用大数字或检索索引的长度)。
def put_me_last(df,column):
    column_list=list(df)
    column_list.remove(column)
    column_list.append(column)
    return df[column_list]  



%timeit put_me_last(df,'b')
1000 loops, best of 3: 391 µs per loop