Вот ваши входные данные:
from scipy.spatial.distance import pdist, squareform
import numpy as np
import pandas as pd
data = {'a': {0: '1.764052', 1: '-0.103219', 2: '0.761038', 3: '-0.103219', 4: '1.240291', 5: '1.532779', 6: '1.230291'}, 'b': {0: '0.400157', 1: '0.410599', 2: '0.121675', 3: '0.410600', 4: '1.202380', 5: '1.469359', 6: '1.202380'}, 'c': {0: '0.978738', 1: '0.144044', 2: '0.443863', 3: '0.144044', 4: '-0.387327', 5: '0.154947', 6: '-0.387327'}, 'd': {0: '2.240893', 1: '1.454274', 2: '0.333674', 3: '1.454274', 4: '-0.302303', 5: '0.378163', 6: '-0.302303'}}
df = pd.DataFrame(data, columns=["a", "b", "c", "d"])
tolerances = {'a': 0.001, 'b': 0.5, 'c': 0.5, 'd': 0.05}
tolerances_values = np.fromiter(tolerances.values(), dtype=float)
>>> print(df)
a b c d
0 1.764052 0.400157 0.978738 2.240893
1 -0.103219 0.410599 0.144044 1.454274
2 0.761038 0.121675 0.443863 0.333674
3 -0.103219 0.410600 0.144044 1.454274
4 1.240291 1.202380 -0.387327 -0.302303
5 1.532779 1.469359 0.154947 0.378163
6 1.230291 1.202380 -0.387327 -0.302303
Вы хотите удалить строки, которые достаточно похожи, на основе предоставленного расстояния: различия между строками не должны быть больше значений, определенных в tolerances
.
from scipy.spatial.distance import pdist, squareform
# Define your similarity function between rows.
def is_similar(x, y):
"""
Returns True if x is similar to y, False else
"""
diffs = np.abs(y-x) # Look at absolute differences
similar = all(diffs <= tolerances_values) # True if all columns diffs are within tolerances
return bool(similar)
# Compute similarities on all your dataframe
similarity_values = pdist(df.to_numpy(), is_similar)
# Convert np.array() into a pd.DataFrame()
similarity_df = pd.DataFrame(squareform(similarity_values), index=df.index, columns= df.index)
# Get indices of similar rows
similar_indices = similarity_df[similarity_df == True].stack().index.tolist()
# Remove symmetric indices (from i,j i,i and j,i only keep i,j)
similar_indices = [sorted(tpl) for tpl in similar_indices if tpl[0] < tpl[1]]
# Flatten
similar_indices = list(set([item for tpl in similar_indices for item in tpl]))
Теперь вот вам go:
>>> df[~df.index.isin(similar_indices)]
a b c d
0 1.764052 0.400157 0.978738 2.240893
2 0.761038 0.121675 0.443863 0.333674
4 1.240291 1.202380 -0.387327 -0.302303
5 1.532779 1.469359 0.154947 0.378163
6 1.230291 1.202380 -0.387327 -0.302303
[устарел] Другой пример использования расстояния cosine_s Similarity
Определить функцию чтобы вычислить сходства и получить индексы, где сходство превышает пороговое значение:
from sklearn.metrics.pairwise import cosine_similarity # any other can be used
def remove_similar(df, distance, threshold):
distance_df = cosine_similarity(df)
similar_indices = [(x,y) for (x,y) in np.argwhere(distance_df>threshold) if x != y]
similar_indices = list(set([item for tpl in similar_indices for item in tpl]))
return df[~df.index.isin(similar_indices)]
Теперь вы можете попробовать с помощью distance=cosine_similarity
и играть с пороговыми значениями:
>>> remove_similar(df, cosine_similarity, 0.9)
a b c d
0 1.764052 0.400157 0.978738 2.240893
2 0.761038 0.121675 0.443863 0.333674
5 1.532779 1.469359 0.154947 0.378163
>>> remove_similar(df, cosine_similarity, 0.9999999)
a b c d
0 1.764052 0.400157 0.978738 2.240893
2 0.761038 0.121675 0.443863 0.333674
4 1.240291 1.202380 -0.387327 -0.302303
5 1.532779 1.469359 0.154947 0.378163
6 1.230291 1.202380 -0.387327 -0.302303