Pandas 允许唯一和非唯一索引。某些操作仅允许唯一索引。在什么情况下使用非唯一索引才有意义?我认为强制执行索引的唯一性可以帮助提前发现数据完整性问题。
免责声明:独特的RangeIndex
永远是性能最好的选择。这个问题似乎倾向于使用唯一索引,并且专门寻找需要允许非唯一索引的情况。因此,从现在开始,不再讨论唯一索引,也不再讨论性能,仅讨论非唯一索引的有用优势。
当我们需要跟踪数据最初来自哪里时,一般情况下非唯一索引是更可取的。很多情况下,在中间阶段,我们需要知道数据位于哪一行。这让我们可以对信息进行计算,如果索引是唯一的,这些信息要么会丢失,要么需要添加额外的列来跟踪它。下面仅举几个例子:
考虑以下 2 个 DataFrame,我们假设每个 DataFrame 代表一天的数据。我们希望按样本编号而不是按天查看每日数据:
df1 = pd.DataFrame([['10:05', 'Day 1', 'Sample 1'],
['11:14', 'Day 1', 'Sample 2']])
df2 = pd.DataFrame([['10:03', 'Day 2', 'Sample 1'],
['11:12', 'Day 1', 'Sample 2']])
Run Code Online (Sandbox Code Playgroud)
# df1
0 1 2
0 10:05 Day 1 Sample 1
1 11:14 Day 1 Sample 2
#df2
0 1 2
0 10:03 Day 2 Sample 1
1 11:12 Day 1 Sample 2
Run Code Online (Sandbox Code Playgroud)
因为 pandas 允许非唯一索引,concat
所以我们可以sort_index
:
pd.concat([df1, df2]).sort_index()
Run Code Online (Sandbox Code Playgroud)
0 1 2
0 10:05 Day 1 Sample 1
0 10:03 Day 2 Sample 1
1 11:14 Day 1 Sample 2
1 11:12 Day 1 Sample 2
Run Code Online (Sandbox Code Playgroud)
请注意,这是按行索引交错两个 DataFrame 的最快方法。另请注意,按列排序是不可行的1
,2
因为单词Day 1
Sample 1
等将按字典顺序排序,这将遇到 、 等值的问题Day 10
,或者需要大量额外的计算才能正确处理数值。
我们可以添加ignore_index=True
to sort_index
,但这只会隐藏新范围索引的覆盖,并且仍然依赖于concat
返回具有非唯一索引的 DataFrame 的事实。
pd.concat([df1, df2]).sort_index(ignore_index=True)
Run Code Online (Sandbox Code Playgroud)
0 1 2
0 10:05 Day 1 Sample 1
1 10:03 Day 2 Sample 1
2 11:14 Day 1 Sample 2
3 11:12 Day 1 Sample 2
Run Code Online (Sandbox Code Playgroud)
explode
,特别是在 Series 上,是一种常见的操作,并且不丢失索引(允许重复)使得扩展和归约类型操作变得更加容易。
目标是删除列中逗号分隔字符串中的任何重复值:
df = pd.DataFrame({
'corresponding_id': [10, 20, 30],
'col': ['a,b,c,a', 'b,c,c,b', 'a,a,a,a']
})
Run Code Online (Sandbox Code Playgroud)
df
:
corresponding_id col
0 10 a,b,c,a
1 20 b,c,c,b
2 30 a,a,a,a
Run Code Online (Sandbox Code Playgroud)
常见的解决方案可能类似于:
df['col'] = (
df['col'].str.split(',').explode()
.groupby(level=0).apply(lambda s: ','.join(np.unique(s)))
)
Run Code Online (Sandbox Code Playgroud)
df
:
corresponding_id col
0 10 a,b,c
1 20 b,c
2 30 a
Run Code Online (Sandbox Code Playgroud)
爆炸后的结果如下:
df['col'].str.split(',').explode()
0 a
0 b
0 c
0 a
1 b
1 c
1 c
1 b
2 a
2 a
2 a
2 a
Name: col, dtype: object
Run Code Online (Sandbox Code Playgroud)
因为存在重复的索引,所以我们可以groupby
相对于level=0
(索引),这只有在保留索引的情况下才可能实现。如果索引不允许重复,我们将有:
0 a
1 b
2 c
3 a
4 b
5 c
6 c
7 b
8 a
9 a
10 a
11 a
Name: col, dtype: object
Run Code Online (Sandbox Code Playgroud)
无法轻松确定值来自哪些行,这使得将它们放回原位变得更加困难。
使用重复标签从 DataFrame 中进行选择的能力对于扩展 DataFrame 非常有帮助。
df = pd.DataFrame({
'Count': [2, 4],
'Value': [1, 6]
})
Run Code Online (Sandbox Code Playgroud)
有时我们需要扩展 DataFrame,在这些情况下我们使用loc
从 DataFrame 中进行选择:
df.loc[[0, 0, 1, 1, 1, 1], :]
Run Code Online (Sandbox Code Playgroud)
注意结果是:
Count Value
0 2 1
0 2 1
1 4 6
1 4 6
1 4 6
1 4 6
Run Code Online (Sandbox Code Playgroud)
我们能够根据重复标签从 DataFrame 中多次选择同一行(并且生成的索引不唯一)。这种情况非常常见,以至于有一种方法Index.repeat
可以根据列动态执行此操作:
df.loc[df.index.repeat(df['Count']), :]
Count Value
0 2 1
0 2 1
1 4 6
1 4 6
1 4 6
1 4 6
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2379 次 |
最近记录: |