d = {'col1': [33,34,35], 'col2': [5,6,8], 'col3': [7,8,9]}
df = pd.DataFrame(data=d)
df[['col1','col3']].head()
使用上面的代码,我可以选择col1
和col3
,但是如果我希望只选择第1行和第3行(使用值[33,35]
和[7,9]
)而不使用任何函数(例如,loc
,iloc
,at
,iat
等。 ) - 纯粹使用数据框索引,例如,df[..,..]
,有没有办法实现这一目标?
使用索引,1
索引第二个元素,使用1
,因为python中的索引以0
开头:
print(df['col1'][1])
更新获取列转置数据框,然后获取列0
和2
,因为转置,然后转置回:
print(df[['col1','col3']].T[[0,2]].T)
要么:
print(df[df.index.isin([0,2])][['col1','col3']])
如上所述,有几种方法可以做到这一点。需要考虑的两点是:从可读性/ Pythonic /惯用的角度来看是有意义的,从绩效的角度来看是有意义的。我可能的解决方案不符合OP的完整规范以避免功能,但我会提供它们供考虑和比较。
让我们看看三种方法,并从两个角度考虑它们。
在这种情况下,为了通过计时代码执行来帮助我们更清楚地看到一些性能方面,我们通过重复存储的值100,000次来增加DataFrame的大小。
import pandas as pd
df = pd.DataFrame({'col1':[32, 33, 34] * 100000,
'col2':[1, 2, 3] * 100000,
'col3':[1, 2, 3] * 100000,
})
方法1
此方法使用@ U9-Forward概述的过程,即按列索引,转置行和列,以便您可以索引所需的行并将DataFrame转换回原始方向。
在Jupyter中使用%timeit
,我们看到这种方法需要多长时间来处理:
[1]: %timeit df[['col1', 'col3']].T[[0, 2]].T
3.02 ms ± 16.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
方法2
此方法基于所需行和索引的列表创建掩码,并基于该掩码过滤DataFrame,然后仅选择所需的列。这与@ jpp的方法有一些相似之处,但不使用.loc
。
同样,使用%timeit
......我们看到这种方法只需要方法1的一半。
[2]: %timeit df[df.index.isin([0, 2])][['col1', 'col3']]
1.61 ms ± 31.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
方法3
第三种方法使用.take()
方法从DataFrame中选择特定行,然后为所需列索引。
再次,使用%timeit
,我们发现这种方法比方法2快三倍,比方法1快六倍。
[1]: %timeit df.take([0, 2])[['col1','col3']]
507 µs ± 5.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
也有争议的是,这种方法比前两种方法更容易阅读。
这会满足您的需求吗? :
df[['col1','col3']][::2]
在这里,我利用了您询问的行索引(0和2)可以表示为切片的事实。但是,对于任意一组行索引,可能无法使其变得简单
iloc
or loc
您希望将整数位置索引与基于标签的索引相结合。这通常很麻烦,但在这里你可以使用iloc
支持整数位置和布尔数组索引的事实:
d = {'col1': [33,34,35], 'col2': [5,6,8], 'col3': [7,8,9]}
df = pd.DataFrame(data=d)
res = df.iloc[[0, 2], df.columns.isin(['col1', 'col3'])]
print(res)
col1 col3
0 33 7
2 35 9
Python中的索引以0
开头,因此第一行和第三行由[0, 2]
表示。
另一种方法是使用loc
和行的布尔索引:
res = df.loc[df.index.isin([0, 2]), ['col1', 'col3']]
由于通常行数超过列数,并且因为整数位置索引自然比基于标签更有效,所以您可能更喜欢iloc
而不是loc
。