팬더 시리즈에서 입력된 숫자에 가장 가까운 값을 찾는 방법은 무엇입니까?
본 적이 있습니다.
이것들은 팬더가 아닌 바닐라 파이썬과 관련이 있습니다.
시리즈가 있는 경우:
ix num
0 1
1 6
2 4
3 5
4 2
그리고 3을 입력합니다. 어떻게 하면 (효율적으로) 찾을 수 있을까요?
- 영상 시리즈에서 발견된 경우 지수는 3입니다.
- 영상 시리즈에서 찾을 수 없는 경우 3보다 낮고 높은 값의 인덱스입니다.
즉, 위의 시리즈 {1,6,4,5,2}와 입력 3을 사용하면 인덱스 (2,4)로 값 (4,2)를 구해야 합니다.
당신은 사용할 수 있습니다.argsort()
맘에 들다
말합니다,input = 3
In [198]: input = 3
In [199]: df.iloc[(df['num']-input).abs().argsort()[:2]]
Out[199]:
num
2 4
4 2
df_sort
는 2개의 가장 가까운 값을 가지는 데이터 프레임입니다.
In [200]: df_sort = df.iloc[(df['num']-input).abs().argsort()[:2]]
색인의 경우,
In [201]: df_sort.index.tolist()
Out[201]: [2, 4]
값의 경우,
In [202]: df_sort['num'].tolist()
Out[202]: [4, 2]
상세, 해결책 에 대하여, ② ③ ④ df
이었다
In [197]: df
Out[197]:
num
0 1
1 6
2 4
3 5
4 2
질문에 완전히 대답하지 않는 것 외에도, 여기서 논의되는 다른 알고리즘의 추가적인 단점은 전체 목록을 정렬해야 한다는 것입니다.이렇게 되면 ~N log(N)의 복잡도가 발생합니다.
그러나 ~N에서도 동일한 결과를 얻을 수 있습니다.이 방법은 데이터 프레임을 원하는 값보다 작은 하나와 큰 두 개의 하위 집합으로 분리합니다.낮은 이웃은 작은 데이터 프레임에서 가장 큰 값보다 크며, 높은 이웃은 그 반대입니다.
이것은 다음과 같은 코드 스니펫을 제공합니다.
def find_neighbours(value, df, colname):
exactmatch = df[df[colname] == value]
if not exactmatch.empty:
return exactmatch.index
else:
lowerneighbour_ind = df[df[colname] < value][colname].idxmax()
upperneighbour_ind = df[df[colname] > value][colname].idxmin()
return [lowerneighbour_ind, upperneighbour_ind]
이 접근 방식은 팬더에서 파티션을 사용하는 것과 유사하며, 이는 대규모 데이터 세트를 다룰 때 정말 유용할 수 있으며 복잡성이 문제가 됩니다.
두 전략을 비교해 보면, 큰 N의 경우 분할 전략이 실제로 더 빠르다는 것을 알 수 있습니다.소규모 N의 경우 훨씬 낮은 수준에서 구현되므로 정렬 전략이 더 효율적일 것입니다.코드 가독성을 높일 수 있는 원라이너이기도 합니다.
이 플롯을 복제하는 코드는 다음과 같습니다.
from matplotlib import pyplot as plt
import pandas
import numpy
import timeit
value=3
sizes=numpy.logspace(2, 5, num=50, dtype=int)
sort_results, partition_results=[],[]
for size in sizes:
df=pandas.DataFrame({"num":100*numpy.random.random(size)})
sort_results.append(timeit.Timer("df.iloc[(df['num']-value).abs().argsort()[:2]].index",
globals={'find_neighbours':find_neighbours, 'df':df,'value':value}).autorange())
partition_results.append(timeit.Timer('find_neighbours(df,value)',
globals={'find_neighbours':find_neighbours, 'df':df,'value':value}).autorange())
sort_time=[time/amount for amount,time in sort_results]
partition_time=[time/amount for amount,time in partition_results]
plt.plot(sizes, sort_time)
plt.plot(sizes, partition_time)
plt.legend(['Sorting','Partitioning'])
plt.title('Comparison of strategies')
plt.xlabel('Size of Dataframe')
plt.ylabel('Time in s')
plt.savefig('speed_comparison.png')
저는 합니다를 사용하는 합니다.iloc
.ix가 먼저 인덱스 레이블을 보기 때문에, 이것은 정렬되지 않은 정수 인덱스에서도 작동하기 때문에 John Galt의 답변에 추가합니다.
df.iloc[(df['num']-input).abs().argsort()[:2]]
영상 시리즈가 이미 정렬되어 있는 경우, 인덱스를 찾는 효율적인 방법은 이등분 함수를 사용하는 것입니다.예:
idx = bisect_left(df['num'].values, 3)
그 열을 생각해 봅시다.col
프레임의터의의df
정렬됩니다.
- 값이 경우.
val
열에요요bisect_left
에는의한를고고를lne에한는의dnftxbisect_right
다음 위치의 인덱스를 반환합니다. - 그 에는 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ 모두
bisect_left
그리고.bisect_right
목록 정렬을 유지하기 위해 값을 삽입할 위치인 동일한 인덱스를 반환합니다.
는 , 에, 는 과 합니다 을 합니다 을 과 는 에 val
인에col
발견된 경우, 발견되지 않은 경우 가장 가까운 값의 인덱스.이 솔루션은 목록의 값이 고유하지 않은 경우에도 작동합니다.
from bisect import bisect_left, bisect_right
def get_closests(df, col, val):
lower_idx = bisect_left(df[col].values, val)
higher_idx = bisect_right(df[col].values, val)
if higher_idx == lower_idx: #val is not in the list
return lower_idx - 1, lower_idx
else: #val is in the list
return lower_idx
이등분 알고리즘은 데이터 프레임 열 "col" 또는 가장 가까운 이웃에서 특정 값 "val"의 인덱스를 찾는 데 매우 효율적이지만, 목록을 정렬해야 합니다.
시리즈가 이미 정렬되어 있다면 이와 같은 것을 사용할 수 있습니다.
def closest(df, col, val, direction):
n = len(df[df[col] <= val])
if(direction < 0):
n -= 1
if(n < 0 or n >= len(df)):
print('err - value outside range')
return None
return df.ix[n, col]
df = pd.DataFrame(pd.Series(range(0,10,2)), columns=['num'])
for find in range(-1, 2):
lc = closest(df, 'num', find, -1)
hc = closest(df, 'num', find, 1)
print('Closest to {} is {}, lower and {}, higher.'.format(find, lc, hc))
df: num
0 0
1 2
2 4
3 6
4 8
err - value outside range
Closest to -1 is None, lower and 0, higher.
Closest to 0 is 0, lower and 2, higher.
Closest to 1 is 0, lower and 2, higher.
을 사용할 수 .numpy.searchsorted
정렬되어 . 되지 된 의 을 할 이 할 을 의 된 pandas.argsort
을 두번 보다 더 .) (가장 가까운 값을 두 번 이상 찾으려는 경우에는 위 방법보다 더 좋습니다.)
정렬이 완료되면 다음과 같이 입력값에 가장 가까운 값을 찾습니다.
indLeft = np.searchsorted(df['column'], input, side='left')
indRight = np.searchsorted(df['column'], input, side='right')
valLeft = df['column'][indLeft]
valRight = df['column'][indRight]
이러한 문제를 해결하기 위해 찾은 가장 직관적인 방법은 @ivo-merchiers가 제안한 파티션 접근 방식을 사용하되 가장 작고 가장 큰 n개를 사용하는 것입니다.정렬되지 않은 영상 시리즈에 대한 작업 외에도 k_matches를 1보다 큰 숫자로 설정하면 여러 개의 근접한 값을 쉽게 얻을 수 있다는 장점이 있습니다.
import pandas as pd
source = pd.Series([1,6,4,5,2])
target = 3
def find_closest_values(target, source, k_matches=1):
k_above = source[source >= target].nsmallest(k_matches+1)
k_below = source[source < target].nlargest(k_matches)
k_all = pd.concat([k_below, k_above]).sort_values()
return k_all
find_closest_values(target, source, k_matches=1)
출력:
4 2
2 4
dtype: int64
에 을 에 가장 가까운 할 경우obj_num
인에'num'
과 선택지가 개일 일우과은른의을로적다을할수nsfncdt수nesreenn,dunsee이을러ee일적우'num'
를 들어 열, 를 'num2'
.
그러려면 새 열을 만드는 것이 좋습니다.'num_diff'
그럼 쓰시오sort_values
. : 에 을 하려고 을 하려고 에 3
인에'num'
열,열,은장은을다에을en에서 가장 작은 값을 합니다.'num2'
◦ 코드아래와 같은 코드:
import pandas as pd
obj_num = 3
df = pd.DataFrame({
'num': [0, 1, 3, 3, 3, 4],
'num2': [0, 0, 0, -1, 1, 0]
})
df_copy = df.loc[:, ['num', 'num2']].copy()
df_copy['num_diff'] = (df['num']-obj_num).abs()
df_copy.sort_values(
by=['num_diff', 'num2'],
axis=0,
inplace=True
)
obj_num_idx = df_copy.index[0]
print(f'Objective row: \n{df.loc[obj_num_idx, :]}')
다음은 목표 값과 열의 딕트를 사용하여 작업을 수행하는 함수입니다(소트에 사용할 열의 순서를 존중합니다).
def colosest_row(df, obj):
'''
Sort df using specific columns given as obj keys.
If a key has None value:
sort column in ascending order.
If a key has a float value:
sort column from closest to farest value from obj[key] value.
Arguments
---------
df: pd.DataFrame
contains at least obj keys in its columns.
obj: dict
dict of objective columns.
Return
------
index of closest row to obj
'''
df_copy = df.loc[:, [*obj]].copy()
special_cols = []
obj_cols = []
for key in obj:
if obj[key] is None:
obj_cols.append(key)
else:
special_cols.append(key)
obj_cols.append(f'{key}_diff')
for key in special_cols:
df_copy[f'{key}_diff'] = (df[key]-obj[key]).abs()
df_copy.sort_values(
by=obj_cols,
axis=0,
ascending=True,
inplace=True
)
return df_copy.index[0]
obj_num_idx = colosest_row(
df=df,
obj={
"num": obj_num,
"num2": None # Sort using also 'num2'
}
)
여기에 많은 답이 있고 그 중에서도 꽤 좋습니다.아무 것도 인정되지 않으며 @Zero의 답변은 현재 가장 높은 평가를 받고 있습니다.또 다른 답변은 인덱스가 아직 정렬되지 않았을 때는 작동하지 않는다고 지적하지만, 더 이상 사용하지 않은 것처럼 보이는 솔루션을 추천합니다.
나는 내가 Numpy 버전을 사용할 수 있다는 것을 발견했습니다.argsort()
인덱스가 정렬되지 않은 경우에도 작동하는 값 자체에 대해 다음과 같은 방식으로 사용할 수 있습니다.
df.iloc[(df['num']-input).abs()..values.argsort()[:2]]
문맥은 제로의 답을 참고하세요.
언급URL : https://stackoverflow.com/questions/30112202/how-do-i-find-the-closest-values-in-a-pandas-series-to-an-input-number
'programing' 카테고리의 다른 글
C의 메모리 누출 감지기? (0) | 2023.09.12 |
---|---|
기존 컨다 가상 환경의 파이썬 버전을 변경하는 방법은? (0) | 2023.09.12 |
Oracle 가입 시 인덱스를 사용하지 않음 (0) | 2023.09.07 |
UNC 경로에서 Get-ChildItem을 실행하면 Powershell에서는 작동하지만 배치 파일에서는 실행되지 않음 (0) | 2023.09.07 |
Oracle sql에서 새 줄 제거 (0) | 2023.09.07 |