我正在尝试构建一个有助于简化研究工作的工具,并且似乎需要检测何时我在一列中的数据中有递增序列,而在另一列中有 asc/desc 序列。
有没有一种干净的方法来检查行中是否有序列,而不必编写像/sf/answers/3687559921/这样迭代行的状态机?编写这样一段代码必须检查一列中的值是否在递增(无间隙),而另一列中的值是否为 asc/desc(无间隙)。我完全能够做到这一点,我只是想知道我的 Pandas 工具箱中是否有我遗漏的东西。
这里有一些例子来阐明我的意图,
import pandas as pd
from collections import namedtuple
QUERY_SEGMENT_ID_COLUMN = 'Query Segment Id'
REFERENCE_SEGMENT_ID_COLUMN = 'Reference Segment Id'
def dataframe(data):
columns = [QUERY_SEGMENT_ID_COLUMN, REFERENCE_SEGMENT_ID_COLUMN]
return pd.DataFrame(data, columns=columns)
# No sequence in either column. No results
data_without_pattern = [[1, 2], [7, 0], [3, 6]]
# Sequence in first column, but no sequence in second column. No results
data_with_pseodo_pattern_query = [[1, 2], [2, 0], [3, 6]]
# Sequence in second column, but no sequence in first column. No results
data_with_pseudo_pattern_reference = [[1, 2], [7, 3], [3, 4]]
# Broken sequence in first column, sequence in second column. No results
data_with_pseudo_pattern_query_broken = [[1, 2], [3, 3], [7, 4]]
# Sequence occurs in both columns, asc. Expect results
data_with_pattern_asc = [[1, 2], [2, 3], [3, 4]]
# Sequence occurs in both columns, desc. Expect results
data_with_pattern_desc = [[1, 4], [2, 3], [3, 2]]
# There is a sequence, and some noise. Expect results
data_with_pattern_and_noise = [[1, 0], [1, 4], [1, 2], [1, 3], [2, 3], [3, 4]]
Run Code Online (Sandbox Code Playgroud)
在第一个例子中,没有任何模式,
print(dataframe(data_without_pattern))
Query Segment Id Reference Segment Id
0 1 2
1 7 0
2 3 6
Run Code Online (Sandbox Code Playgroud)
第二个示例在查询列中具有升序的 id 序列,但在引用列中没有,
print(dataframe(data_with_pseodo_pattern_query))
Query Segment Id Reference Segment Id
0 1 2
1 2 0
2 3 6
Run Code Online (Sandbox Code Playgroud)
第三个示例与前一个示例相同,但针对参考列。
print(dataframe(data_with_pseudo_pattern_reference))
Query Segment Id Reference Segment Id
0 1 2
1 7 3
2 3 4
Run Code Online (Sandbox Code Playgroud)
在这里,参考列中有一个升序,而查询列中的 id 也按升序排列,但存在间隙,因此不会产生任何结果
print(dataframe(data_with_pseudo_pattern_query_broken))
Query Segment Id Reference Segment Id
0 1 2
1 3 3
2 7 4
Run Code Online (Sandbox Code Playgroud)
这里有两个“完美”的例子,其中查询列按升序排列,不间断,参考列分别按降序和升序排列。结果在意料之中。
print(dataframe(data_with_pattern_asc))
Query Segment Id Reference Segment Id
0 1 2
1 2 3
2 3 4
print(dataframe(data_with_pattern_desc))
Query Segment Id Reference Segment Id
0 1 4
1 2 3
2 3 2
Run Code Online (Sandbox Code Playgroud)
最终,一个数据不太干净但仍然存在所需模式的案例
print(dataframe(data_with_pattern_and_noise))
Query Segment Id Reference Segment Id
0 1 0
1 1 4
2 1 2
3 1 3
4 2 3
5 3 4
Run Code Online (Sandbox Code Playgroud)
这个最新的案例可能需要进一步解释。我在这里的目的,是要回到一个类似于q=(1, 3), r=(2, 4),例如(start, end) 值从各自的列(不索引)。
我在想是否有可能进行一系列良好的group_by操作,但我没有只见树木不见森林。
我认为这个问题具有社区价值,因为我找不到类似的问题,即有人在多列的行中寻找模式。
编辑:来自评论的案例(@code-不同)
对于数据框,
data_with_multiple_contiguous_sequences = [[1, 1], [2, 2], [3, 3], [0, 4], [1, 5], [2, 6], [3, 7], [4, 8]]
Query Segment Id Reference Segment Id
0 1 1
1 2 2
2 3 3
3 0 4
4 1 5
5 2 6
6 3 7
7 4 8
Run Code Online (Sandbox Code Playgroud)
目标是识别两个序列。意思是我们想要 yield q1=(1, 3), r1=(1, 3), q2=(0, 4), r2=(4, 8)。
如果我理解正确的话,你的问题是岛屿和缺口问题的一个变体。每个具有可接受间隙的单调(递增或递减)子序列将形成一个岛。例如,给定一个系列s:
s island
-- ------
0 1
0 1
1 1
3 2 # gap > 1, form new island
4 2
2 3 # stop increasing, form new island
1 3
0 3
Run Code Online (Sandbox Code Playgroud)
概括来说:每当当前行和前一行之间的间隙超出 [-1, 1] 范围时,就会形成一个新岛。
Query Segment Id在和上应用间隙岛算法Reference Segment Id:
Query Segment Id Q Island Reference Segment Id R Island Q-R Intersection
---------------- -------- -------------------- -------- ----------------
1 1 1 1 (1, 1)
2 1 2 1 (1, 1)
3 1 3 1 (1, 1)
0 2 4 1 (2, 1)
1 2 5 1 (2, 1)
2 2 6 1 (2, 1)
3 2 7 1 (2, 1)
4 2 8 1 (2, 1)
0 3 9 1 (3, 1)
Run Code Online (Sandbox Code Playgroud)
您要查找的 和 范围现在是每个的开头和结尾处q的和。但最后需要注意的是:忽略长度为 1 的交集(如最后一个交集)。rQuery Segment IdReference Segment IdQ-R Intersection
代码:
columns = ['Query Segment Id', 'Reference Segment Id']
df = pd.DataFrame(data_with_multiple_contiguous_sequences, columns=columns)
def get_island(col):
return (~col.diff().between(-1,1)).cumsum()
df[['Q Island', 'R Island']] = df[['Query Segment Id', 'Reference Segment Id']].apply(get_island)
result = df.groupby(['Q Island', 'R Island']) \
.agg(**{
'Q Start': ('Query Segment Id', 'first'),
'Q End': ('Query Segment Id', 'last'),
'R Start': ('Reference Segment Id', 'first'),
'R End': ('Reference Segment Id', 'last'),
'Count': ('Query Segment Id', 'count')
}) \
.replace({'Count': 1}, {'Count': np.nan}) \
.dropna()
result['Q'] = result[['Q Start', 'Q End']].apply(tuple, axis=1)
result['R'] = result[['R Start', 'R End']].apply(tuple, axis=1)
Run Code Online (Sandbox Code Playgroud)
结果:
Q Start Q End R Start R End Count Q R
Q Island R Island
1 1 1 3 1 3 3 (1, 3) (1, 3)
2 1 0 4 4 8 5 (0, 4) (4, 8)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
184 次 |
| 最近记录: |