2017-11-23 9 views
3

팬더 데이터 프레임에 다음과 같은 제품 설명이 있다고 가정 해 봅니다. 나는 다음과 같은 조건을 만족하는 모든 제품의 제품 설명을 계속하고 싶습니다 : 모든 id를 들어Python의 설명 시나리오 및 상태를 기반으로 제품 필터링

product_descriptions에, 그것은 scenario_descriptions의 모든 descriptions 적어도 1 에서 시나리오가 포함되어 있는지 확인하세요. 그렇다면 모든 의 설명은 이러한 시나리오가 status 4, 5 또는 6이있는 경우, 확인

입력

scenario_descriptions = [ 
    ['world1', 'world2', 'world3'], #scenario1 
    ['world4', 'world2'],   #scenario2 
    ['world5'],      #scenario3 
    ['world6', 'world7'],   #scenario4 
    ['world6', 'world2']    #scenario5 
] 

product_descriptions = 

id | description | status 
------------------------- 
1 | world1  | 1 
1 | world2  | 4 
1 | world3  | 1 
1 | world4  | 4 
1 | world5  | 4 
1 | world6  | 4 
1 | world7  | 1 
1 | world8  | 4 
1 | world9  | 4 
1 | world10  | 4 
1 | world11  | 4 
1 | world12  | 4 
1 | world13  | 4 
1 | world14  | 4 
1 | world15  | 1 
2 | world1  | 1 
2 | world2  | 1 
2 | world3  | 5 
2 | world15  | 6 
2 | world8  | 6 
2 | world4  | 5 
2 | world7  | 5 

ID == 1이 제외되지 않은 제품으로 인해 :

  • world2 and world4` (scenario2)이고 상태는 4
  • 입니다. 보유 상태 world5 (scenario3) 4
  • 이 갖는 상태 world6world2 (scenario5) 4- 때문에 == 2 제외 제품 ID와

:

  • world1 (시나리오 1)가 '케이
  • (시나리오 2)는 상태 4, 5 또는 6
  • 없는 world2 그것은없는 t는 상태 4, 5 또는 6을 34,443,210 (scenario3)
  • 그것은 world6 (scenario4)는
  • 그것은 world6 (scenario5) 및 world2 상태 4, 5 또는 6

출력

없는없는없는
filtered_product_descriptions = 

id | description | status 
------------------------- 
1 | world1  | 1 
1 | world2  | 4 
1 | world3  | 1 
1 | world4  | 4 
1 | world5  | 4 
1 | world6  | 4 
1 | world7  | 1 
1 | world8  | 4 
1 | world9  | 4 
1 | world10  | 4 
1 | world11  | 4 
1 | world12  | 4 
1 | world13  | 4 
1 | world14  | 4 
1 | world15  | 1 

어떻게 해결할 수 있을까요? 며칠 동안 노력했지만 성공하지 못했습니다. ( 아래 코드는 내가 얻을 수있는 가장 가까운 부분입니다.이 문제는 첫 번째 문제를 해결합니다.이 두 번째 조건을 결합하는 방법을 모르겠습니다.

이 경우 모든 시나리오의 설명에 상태 4, 5 또는 6이 있는지 확인하십시오.

filtered_product_descriptions = (product_descriptions.groupby('id').filter(lambda x: (pd.Series([(pd.Series(y).isin(x['description']).all()) for y in scenario_descriptions])).any())) 

답변

1

사용 :

#create dictionary by scenaries 
d = {'scenario{}'.format(k):v for k, v in enumerate(scenario_descriptions, 1)} 

#unique id for reindex 
uniq_id = df['id'].unique() 

def f(x): 
    #check if all description 
    c = set(x['description']) >= set(v) 
    #check if 4,5 or 6 value 
    d = x['status'].isin([4,5,6]).all() 
    return (c & d) 

d1 = {} 
for k, v in d.items(): 
    #filter df by scenary first for remove not relevant rows 
    a = df[df['description'].isin(v)] 
    #call groupby with custom function 
    b = a.groupby('id').apply(f) 
    #add missing ids and fill by False 
    #output to dictionary 
    d1[k] = b.reindex(uniq_id, fill_value=False) 

print (d1) 
{'scenario1': id 
1 False 
2 False 
dtype: bool, 'scenario4': id 
1 False 
2 False 
dtype: bool, 'scenario5': id 
1  True 
2 False 
dtype: bool, 'scenario3': id 
1  True 
2 False 
dtype: bool, 'scenario2': id 
1  True 
2 False 
dtype: bool} 

#reduce dict to DataFrame and check at least one True per row 
m = pd.concat(d1, axis=1).any(axis=1) 
print (m) 
id 
1  True 
2 False 

#last filtering 
df = df[df['id'].isin(m.index[m])] 
print (df) 
    id description status 
0 1  world1  1 
1 1  world2  4 
2 1  world3  1 
3 1  world4  4 
4 1  world5  4 
5 1  world6  4 
6 1  world7  1 
7 1  world8  4 
8 1  world9  4 
9 1  world10  4 
10 1  world11  4 
11 1  world12  4 
12 1  world13  4 
13 1  world14  4 
14 1  world15  1 
0

사용

In [260]: product_descriptions.groupby('id').filter(
    ...: lambda x: all(any(w in x.description.values for w in L) 
    ...:     for L in scenario_descriptions)) 
Out[260]: 
    id description status 
0 1  world1  1 
1 1  world2  4 
2 1  world3  1 
3 1  world4  4 
4 1  world5  4 
5 1  world6  4 
6 1  world7  1 
7 1  world8  4 
8 1  world9  4 
9 1  world10  4 
10 1  world11  4 
11 1  world12  4 
12 1  world13  4 
13 1  world14  4 
14 1  world15  1 
+0

어디에서 4,5,6 상태를 확인합니까? – dunkubok