본문 바로가기
DataScience/머신러닝

머신러닝 :: 머신러닝 추천 서비스 구현_데이터 필터링, 쿼리셋 다루기 _TIL67

by 올커 2022. 12. 8.

■ JITHub 개발일지 67일차

□  TIL(Today I Learned) ::

 머신러닝 추천 서비스 구현_데이터 필터링, 쿼리셋 다루기

 1. 데이터 필터링

  - 특정 문자열과 일치

filter = df['col_name'] == 'check_data'
result = df[filter]

  - 특정 문자열 포함

filter = df['col_name'].str.contains('str1|str2|str3')
result = df[filter]

  - 특정 문자열을 제외

filter = df['col_name'].str.contains('str1|str2|str3')
result = df[~filter]

 ※ 쿼리셋 안에서 특정 문자 포함여부 확인(__contains를 사용한다.)

            for i in range(0, 12):
                pick = Place.objects.filter(place_address__contains=CHOICE_CATEGORY[choice_no-1][1],category=CHOICE_CATEGORY[i][1]).first()
                place_list.append(pick.id)

 

2. 쿼리셋 정렬 (order_by)

User.objects.all().order_by('created_at') 	# 오름차순
User.objects.all().order_by('-created_at') 	# 내림차순

3. Django ORM에서 쿼리셋 커스텀 정렬할 경우 (*참고 링크)

from django.db.models import Case, When

# pk_list에 적힌 순서대로 정렬하고자 할 경우
pk_list = [1, 4, 3]
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pk_list)])
queryset = MyModel.objects.filter(pk__in=pk_list).order_by(preserved)

4. json파일을 DB에 적용하고자 하는데 아래와 같이 UTF-8 코덱과 일치하지 않아 Decode가 불가하다는 에러가 발생했다.

python manage.py loaddata places.json
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb2 in position 62: invalid start byte

  - 해결방법은 간단했다. 메모장에서 해당 파일을 열고 다른 이름으로 저장시 아래 인코딩을 UTF-8로 변경하면 된다.

 

5. 쿼리셋 (*참고 링크

아래는 오늘 만들었던 취향선택을 위한 코드이다.

# views.py

##### 취향 선택 #####
class PlaceSelectView(APIView):
    #맛집 취향 선택(리뷰가 없거나, 비로그인 계정일 경우)
    def get(self, request, choice_no):
        place_list = []
        # 지역 선택일 경우
        if choice_no > 12:
            place_list = []
            for i in range(0, 12):
                pick = Place.objects.filter(place_address__contains=CHOICE_CATEGORY[choice_no-1][1],category=CHOICE_CATEGORY[i][1]).first()
                place_list.append(pick.id)
            preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(place_list)])
            place = Place.objects.filter(id__in=place_list).order_by(preserved)
            serializer = PlaceSelectSerializer(place, many=True)
            return Response(serializer.data, status=status.HTTP_200_OK)
        # 음식 선택일 경우
        else:
            if (choice_no == 3)|(choice_no == 6)|(choice_no == 12):
                place_list = []
                pick1 = Place.objects.filter(category=CHOICE_CATEGORY[choice_no-1][1])[0:3]
                pick2 = Place.objects.filter(category=CHOICE_CATEGORY[choice_no-2][1])[0:3]
                pick3 = Place.objects.filter(category=CHOICE_CATEGORY[choice_no-3][1])[0:3]
                pick = (pick1|pick2|pick3)
                serializer = PlaceSelectSerializer(pick, many=True)
                return Response(serializer.data, status=status.HTTP_200_OK)
            else:
                place_list = []
                pick = Place.objects.filter(category=CHOICE_CATEGORY[choice_no-1][1])[0:12]
                print(pick)
                serializer = PlaceSelectSerializer(pick, many=True)
                return Response(serializer.data, status=status.HTTP_200_OK)

 - 쿼리셋의 첫번째 항목만 가져올 경우는 .first()를 사용하고, 쿼리셋의 0~x인덱스까지 가져올 경우 위의 코드와 같이 인덱스 슬라이싱으로 가져올 수 있었다.

 - 또, 쿼리셋 병합이 가능한데 위의 pick = (pick1|pick2|pick3}과 같이 '|' 문자를 사용하거나, union 함수를 이용하기도 한다.

 

 

6. 가장 짜증났던 오류

 - 위의 코드를 작성하면서 다양한 오류를 접했다.

 - 예를들면 아래 오류. 'NoneType' object has no attribute 'id'

 - 분명히 위에 30~147과 같이 id를 읽어오고 있는데 왜 Nonetype이라는거지?

쿼리셋을 다시 뽑아보니 아래와 같이 None이 맨 마지막에 하나 숨어있었다. 인덱스가 out of range된 탓으로, 인덱스를 다시 조정하고 나서 해결할 수 있었다.

 

반응형

댓글