在熊猫中按名称将列移动到表格的前面
Posted
技术标签:
【中文标题】在熊猫中按名称将列移动到表格的前面【英文标题】:Move column by name to front of table in pandas 【发布时间】:2014-09-27 03:05:13 【问题描述】:这是我的 df:
Net Upper Lower Mid Zsore
Answer option
More than once a day 0% 0.22% -0.12% 2 65
Once a day 0% 0.32% -0.19% 3 45
Several times a week 2% 2.45% 1.10% 4 78
Once a week 1% 1.63% -0.40% 6 65
如何按名称 ("Mid"
) 将列移动到表的前面,索引 0。结果应该是这样的:
Mid Upper Lower Net Zsore
Answer option
More than once a day 2 0.22% -0.12% 0% 65
Once a day 3 0.32% -0.19% 0% 45
Several times a week 4 2.45% 1.10% 2% 78
Once a week 6 1.63% -0.40% 1% 65
我当前的代码使用df.columns.tolist()
按索引移动列,但我想按名称移动它。
【问题讨论】:
【参考方案1】:我们可以使用ix
通过传递一个列表来重新排序:
In [27]:
# get a list of columns
cols = list(df)
# move the column to head of list using index, pop and insert
cols.insert(0, cols.pop(cols.index('Mid')))
cols
Out[27]:
['Mid', 'Net', 'Upper', 'Lower', 'Zsore']
In [28]:
# use ix to reorder
df = df.ix[:, cols]
df
Out[28]:
Mid Net Upper Lower Zsore
Answer_option
More_than_once_a_day 2 0% 0.22% -0.12% 65
Once_a_day 3 0% 0.32% -0.19% 45
Several_times_a_week 4 2% 2.45% 1.10% 78
Once_a_week 6 1% 1.63% -0.40% 65
另一种方法是引用该列并将其重新插入到前面:
In [39]:
mid = df['Mid']
df.drop(labels=['Mid'], axis=1,inplace = True)
df.insert(0, 'Mid', mid)
df
Out[39]:
Mid Net Upper Lower Zsore
Answer_option
More_than_once_a_day 2 0% 0.22% -0.12% 65
Once_a_day 3 0% 0.32% -0.19% 45
Several_times_a_week 4 2% 2.45% 1.10% 78
Once_a_week 6 1% 1.63% -0.40% 65
您也可以使用loc
来实现相同的结果,因为ix
将在未来版本的pandas 中从0.20.0
开始被弃用:
df = df.loc[:, cols]
【讨论】:
.loc
上的信息应该排在最前面,而不是 .ix
【参考方案2】:
也许我遗漏了一些东西,但其中很多答案似乎过于复杂。您应该能够只在单个列表中设置列:
列在前面:
df = df[ ['Mid'] + [ col for col in df.columns if col != 'Mid' ] ]
或者,如果您想将其移到后面:
df = df[ [ col for col in df.columns if col != 'Mid' ] + ['Mid'] ]
或者,如果您想移动多个列:
cols_to_move = ['Mid', 'Zsore']
df = df[ cols_to_move + [ col for col in df.columns if col not in cols_to_move ] ]
【讨论】:
对于其他任何人,请确保为多个列使用选项 3。具有多个列的选项 1 不会从原始位置的列中删除Mid
和 Zscore
。当同一列出现两次时,我在尝试分组时发现了 Grouper
错误。【参考方案3】:
我更喜欢这个解决方案:
col = df.pop("Mid")
df.insert(0, col.name, col)
与其他建议的答案相比,它更易于阅读且速度更快。
def move_column_inplace(df, col, pos):
col = df.pop(col)
df.insert(pos, col.name, col)
绩效评估:
对于此测试,当前的最后一列在每次重复中移到前面。就地方法通常表现更好。虽然 citynorman 的解决方案可以就地实现,但 Ed Chum 的基于.loc
的方法和 sachinnm 的基于reindex
的方法却不能。
虽然其他方法是通用的,但 citynorman 的解决方案仅限于 pos=0
。我没有观察到 df.loc[cols]
和 df[cols]
之间的任何性能差异,这就是我没有提供其他建议的原因。
我在 MacBook Pro(2015 年中)上使用 python 3.6.8 和 pandas 0.24.2 进行了测试。
import numpy as np
import pandas as pd
n_cols = 11
df = pd.DataFrame(np.random.randn(200000, n_cols),
columns=range(n_cols))
def move_column_inplace(df, col, pos):
col = df.pop(col)
df.insert(pos, col.name, col)
def move_to_front_normanius_inplace(df, col):
move_column_inplace(df, col, 0)
return df
def move_to_front_chum(df, col):
cols = list(df)
cols.insert(0, cols.pop(cols.index(col)))
return df.loc[:, cols]
def move_to_front_chum_inplace(df, col):
col = df[col]
df.drop(col.name, axis=1, inplace=True)
df.insert(0, col.name, col)
return df
def move_to_front_elpastor(df, col):
cols = [col] + [ c for c in df.columns if c!=col ]
return df[cols] # or df.loc[cols]
def move_to_front_sachinmm(df, col):
cols = df.columns.tolist()
cols.insert(0, cols.pop(cols.index(col)))
df = df.reindex(columns=cols, copy=False)
return df
def move_to_front_citynorman_inplace(df, col):
# This approach exploits that reset_index() moves the index
# at the first position of the data frame.
df.set_index(col, inplace=True)
df.reset_index(inplace=True)
return df
def test(method, df):
col = np.random.randint(0, n_cols)
method(df, col)
col = np.random.randint(0, n_cols)
ret_mine = move_to_front_normanius_inplace(df.copy(), col)
ret_chum1 = move_to_front_chum(df.copy(), col)
ret_chum2 = move_to_front_chum_inplace(df.copy(), col)
ret_elpas = move_to_front_elpastor(df.copy(), col)
ret_sach = move_to_front_sachinmm(df.copy(), col)
ret_city = move_to_front_citynorman_inplace(df.copy(), col)
# Assert equivalence of solutions.
assert(ret_mine.equals(ret_chum1))
assert(ret_mine.equals(ret_chum2))
assert(ret_mine.equals(ret_elpas))
assert(ret_mine.equals(ret_sach))
assert(ret_mine.equals(ret_city))
结果:
# For n_cols = 11:
%timeit test(move_to_front_normanius_inplace, df)
# 1.05 ms ± 42.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit test(move_to_front_citynorman_inplace, df)
# 1.68 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit test(move_to_front_sachinmm, df)
# 3.24 ms ± 96.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum, df)
# 3.84 ms ± 114 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_elpastor, df)
# 3.85 ms ± 58.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum_inplace, df)
# 9.67 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# For n_cols = 31:
%timeit test(move_to_front_normanius_inplace, df)
# 1.26 ms ± 31.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_citynorman_inplace, df)
# 1.95 ms ± 260 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_sachinmm, df)
# 10.7 ms ± 348 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum, df)
# 11.5 ms ± 869 µs per loop (mean ± std. dev. of 7 runs, 100 loops each
%timeit test(move_to_front_elpastor, df)
# 11.4 ms ± 598 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum_inplace, df)
# 31.4 ms ± 1.89 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
【讨论】:
很好的解决方案。但是,我们不应该将带有插入列的修改后的 df 显式分配给原始 df。所以我们需要使用df.insert(0, col.name, col)
,而不是df = df.insert(0, col.name, col)
。不过,您在 move_column_inplace()
函数中正确使用了它。
谢谢@normanius。我知道在德克斯特的实验室里一直在努力工作。 :-) 很好的解决方案。奥卡姆剃刀。简洁大方。
我也更喜欢这个解决方案 :)【参考方案4】:
您可以在 pandas 中使用 df.reindex() 函数。 df是
Net Upper Lower Mid Zsore
Answer option
More than once a day 0% 0.22% -0.12% 2 65
Once a day 0% 0.32% -0.19% 3 45
Several times a week 2% 2.45% 1.10% 4 78
Once a week 1% 1.63% -0.40% 6 65
定义列名列表
cols = df.columns.tolist()
cols
Out[13]: ['Net', 'Upper', 'Lower', 'Mid', 'Zsore']
将列名移动到您想要的任何位置
cols.insert(0, cols.pop(cols.index('Mid')))
cols
Out[16]: ['Mid', 'Net', 'Upper', 'Lower', 'Zsore']
然后使用df.reindex()
函数重新排序
df = df.reindex(columns= cols)
输出是:df
Mid Upper Lower Net Zsore
Answer option
More than once a day 2 0.22% -0.12% 0% 65
Once a day 3 0.32% -0.19% 0% 45
Several times a week 4 2.45% 1.10% 2% 78
Once a week 6 1.63% -0.40% 1% 65
【讨论】:
【参考方案5】:我不喜欢在其他解决方案中明确指定所有其他列的方式,因此这对我来说效果最好。虽然对于大型数据帧可能会很慢...?
df = df.set_index('Mid').reset_index()
编辑: 另一种更快、更灵活的解决方案
cfg_col_sel = ['Mid', 'Zscore']
cfg_col_sel = cfg_col_sel+[s for s in df.columns if not s in cfg_col_sel]
df = df[cfg_col_sel]
【讨论】:
这利用了当前版本的reset_index()
在第一个位置插入删除的索引。但请注意,docs 中未指定此行为。
性能看我的回答。对set_index()
和reset_index()
使用inplace=True
是有利的。【参考方案6】:
这是一组我经常用来重新排列列位置的通用代码。您可能会发现它很有用。
cols = df.columns.tolist()
n = int(cols.index('Mid'))
cols = [cols[n]] + cols[:n] + cols[n+1:]
df = df[cols]
【讨论】:
理想情况下,解释你的答案以及是什么使它成为一个好的解决方案,而不仅仅是发布一段代码。你冒着被否决的风险【参考方案7】:要重新排序 DataFrame 的行,只需使用如下列表。
df = df[['Mid', 'Net', 'Upper', 'Lower', 'Zsore']]
这使得稍后阅读代码时所做的事情变得非常明显。同时使用:
df.columns
Out[1]: Index(['Net', 'Upper', 'Lower', 'Mid', 'Zsore'], dtype='object')
然后剪切并粘贴以重新排序。
对于具有许多列的 DataFrame,将列列表存储在变量中,并将所需列弹出到列表的前面。这是一个例子:
cols = [str(col_name) for col_name in range(1001)]
data = np.random.rand(10,1001)
df = pd.DataFrame(data=data, columns=cols)
mv_col = cols.pop(cols.index('77'))
df = df[[mv_col] + cols]
现在df.columns
有。
Index(['77', '0', '1', '2', '3', '4', '5', '6', '7', '8',
...
'991', '992', '993', '994', '995', '996', '997', '998', '999', '1000'],
dtype='object', length=1001)
【讨论】:
如果您使用由 1001 列组成的 DataFrame 会怎样? 这个概念是一样的,但是对于很多列,列应该存储在一个列表中,并且应该对列表进行操作。有关示例,请参见我上面的编辑。我的示例实际上与***.com/a/51009742/5827921 相同。【参考方案8】:df.set_index('Mid').reset_index()
这似乎是一个非常简单的方法。
【讨论】:
【参考方案9】:如果你想将一列移到数据框的前面e,你可以使用
使用set_index()
。
df.set_index(df.pop('column_name'), inplace=True)
df.reset_index(inplace=True)
您首先需要将要放在前面的列设置为数据框的索引(我们执行pop
以便在将其设置为索引之前从原始数据框中删除该列,以便避免在下一个操作中发生名称冲突),最后调用reset_index()
使旧索引成为数据帧的第一列。
更多详情请见How to change the order of dataframe columns in pandas。
【讨论】:
【参考方案10】:这是一个非常简单的答案。
不要忘记列名周围的两个 (()) '括号'。否则,它会给你一个错误。
# here you can add below line and it should work
df = df[list(('Mid','Upper', 'Lower', 'Net','Zsore'))]
df
Mid Upper Lower Net Zsore
Answer option
More than once a day 2 0.22% -0.12% 0% 65
Once a day 3 0.32% -0.19% 0% 45
Several times a week 4 2.45% 1.10% 2% 78
Once a week 6 1.63% -0.40% 1% 65
【讨论】:
显然 OP 不想明确拼出列名。在某些数据帧非常宽的情况下,这甚至可能是不可能的。【参考方案11】:如果您想移动到另一个地方并重新分配名称,您可以执行以下操作:
df.insert(0, 'new col name', col)
df.pop("Mid")
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.insert.html
【讨论】:
【参考方案12】:您可以尝试的最简单的方法是:
df=df[[ 'Mid', 'Upper', 'Lower', 'Net' , 'Zsore']]
【讨论】:
以上是关于在熊猫中按名称将列移动到表格的前面的主要内容,如果未能解决你的问题,请参考以下文章