파이썬 코딩 한줄

[pandas apply] 텍스트를 일정 길이만큼 잘라서 분리하기

soopy 2022. 10. 14. 14:50
728x90

 

 

만약 위와 같이 각 seq(시퀀스)별로 엄청 긴 문장의 text가 포함된 df가 있다고 가정합니다.
텍스트를 만약 길이(len) 20 단위로 잘라서 데이터프레임으로 만들기 위해서는 어떻게 해야 할까요?

 

각 텍스트의 총 길이 보기

df['len'] = df['text'].apply(len)
df

apply 와 len 함수를 쓰면 간단하게 text의 총 길이를 출력할 수 있습니다.
각 text의 길이를 알면 몇 번 잘라야 되는지 알 수 있기 때문입니다.

저희는 길이 20 단위로 자를 예정이므로
153 // 20을 하면 7이 나오게 되는데 7번 자르면 마지막에 길이 13인 텍스트가 남게되므로
이것도 챙기려면 7 + 1 총 8번 쪼개야 함을 알 수 있습니다.

 

텍스트 자르기 함수 작성

def func(seq, text, length, cut=20):
    _iter = length // cut
    result = []
    sep_num = 0 # 몇번째 잘림(?) 인지 확인하기 위해 남겨둡니다.
    
    for i in range(_iter + 1):
        sliced = text[cut*i : cut*(i+1)]
        
        result.append([seq, sliced, sep_num])
        sep_num += 1
    
    return result

func 함수에 seq와 text, 텍스트의 총 길이(length), 그리고 자를 길이 단위를 입력값으로 받습니다.
_iter를 통해 각 텍스트를 길이 20만큼 자르려면 몇 번 잘라야 하는지 계산합니다.

for문을 돌면서 text를 20 단위로 잘라서 seq와 sep_num와 함께 리스트로 묶어서
result라는 리스트에 담아 줍니다. 그러면 리스트 안에 분리된 결과 리스트가 차곡차곡 담겨집니다.
참고로 sep_num는 텍스트가 분리된 구간을 구분하기 위함입니다.

이중 리스트로 담는 이유는 나중에 DataFrame으로 담기 용이하기 때문입니다.

 

함수 적용하기

result = df.apply(lambda x: func(x['seq'], x['text'], x['len'], cut=20), axis=1)

이제 df 자체를 apply에 넣어줍니다. 이때 axis=1로 하면 데이터프레임의 row 별로 꺼내줍니다.
그러면 해당 컬럼명을 지정해 주면 해당 값을 위와 같이 다중으로 뽑아 쓸 수 있게 됩니다.
위 결과를 보시면 첫번째 row의 텍스트 분리 결과, 두번째 row의 텍스트 분리결과...를 볼 수 있습니다.

 

pd.DataFrame(result[0])

result 결과를 하나 뽑아서 데이터프레임으로 만들면 위와 같이 됩니다.
153자의 텍스트를 20 단위로 잘 쪼갠 것을 확인할 수 있습니다.
이제 각 텍스트 분리 결과를 데이터프레임으로 만들어서 하나로 합쳐주면 끝입니다.

 

최종 데이터프레임 만들기

final_df = pd.DataFrame() # 빈 df, 최종 df가 될 예정

for row in result:
    temp = pd.DataFrame(row)
    final_df = pd.concat([final_df, temp])

# 합친 df의 컬럼명 지어주기
final_df.columns = ['seq', 'text', 'sep_num']
# 최종적으로 잘 잘랐는지 길이 확인을 위한 len 컬럼 생성
final_df['len'] = final_df['text'].apply(len)
# 인덱스 번호 재정렬하기
final_df = final_df.reset_index(drop=True)

final_df

 

result 결과를 하나씩 꺼래서 데이터프레임을 만들어주고, 차곡차곡 쌓아서(concat) 하나로 만듭니다.
추가적으로 잘 잘라줬는지 한번 더 apply(len)을 통해 확인해주고,
인덱스 번호를 리셋해 줍니다.

 

결과는 아래와 같이 나왔습니다! (사진이 너무 길어져서 세번째 row 결과는 잘랐습니다.)

728x90
728x90