판다스 데이터프레임 컬럼에 리스트형태를 입력하고 저장한 후
다시 읽어오면, 해당 형식은 문자열이다 -> "[1, 2, 3, 4]"
이걸 다시 리스트화 시키는 방법에 대해서 작성하겠다.
우선 리스트가 들어있는 데이터 프레임을 생성해 보겠다.
여기서 열은 '회원 컬럼' 이고 총 3개의 다른 리스트가 들어있는 행이 생성된다.
import pandas as pd
from ast import literal_eval
df = pd.DataFrame({'회원 컬럼':[['홍길동', '10', '남'], ['이정재', '20', '남'], ['하정우', '30', '남']]})
df.info()
Dtype 은 object 로 나온다.
행 안에 있는 데이터의 타입을 보면 list 형태인 것을 확인할 수 있다.
df['회원 컬럼'][0]
>> ['홍길동', '10', '남']
type(df['회원 컬럼'][0])
>> list
이제 여기까지 데이터를 만들었으니 다음에 이어서 해야지~ 하고 저장을 한 후에 df2로 불러오기를 해보자.
df.to_csv('연예인.csv', index=False, sep = '\t')
df2 = pd.read_csv('./연예인.csv', sep='\t')
이렇게만 보았을때 회원 컬럼의 각 행은 리스트로 보이는게 함정이다...
역시 0번 행의 형태를 보면 str로 보인다.
df2['회원 컬럼'][0]
>> "['홍길동', '10', '남']"
type(df2['회원 컬럼'][0])
>> str
ast 의 literal_eval 은 이 문제를 아주 간단하게 해결해주는 도구이다.
다음은 pandas의 apply와 lambda를 활용해서 전체 열 값에 한번에 literal_eval을 적용하는 코드이다.
항상 데이터프레임을 읽어올때, 리스트로 보이는 값들이 있으면, 꼭 한번 확인해보는 습관을 들이는게 중요해 보인다.
df2['회원 컬럼'] = df2['회원 컬럼'].apply(lambda x : literal_eval(x))
df2['회원 컬럼'][0]
>> ['홍길동', '10', '남']
type(df2['회원 컬럼'][0])
>> list
그럼 이제 ast가 도대체 뭔지? 에 대해서 살펴보자..
ast — Abstract Syntax Trees
vscode에서 ctrl 을 누른뒤 import 하는 ast 를 클릭하여 조금 더 깊이 들어가면 docstring으로 된 친절한 설명? 을 만나볼 수 있다.
google 번역 성능이 날이갈 수록 좋아지는걸 느낀다..(번역할 필요를 못느낄정도로..)
'ast' 모듈은 Python 애플리케이션이 Python 추상 구문 문법 트리를 처리하는 데 도움이 됩니다.
추상 구문 자체는 Python 릴리스마다 변경될 수 있습니다.
이 모듈은 현재 문법이 어떻게 생겼는지 프로그래밍 방식으로 알아내고 수정할 수 있도록 도와줍니다.
추상 구문 트리는 `ast.PyCF_ONLY_AST`를 플래그로 `compile()` 내장 함수에 전달하거나 이 모듈의 `parse()` 함수를 사용하여 생성할 수 있습니다.
결과는 모든 클래스가 `ast.AST`에서 상속되는 객체 트리가 됩니다.
수정된 추상 구문 트리는 내장 `compile()` 함수를 사용하여 Python 코드 객체로 컴파일할 수 있습니다.
또한 트리 작업을 더 간단하게 만드는 다양한 도우미 기능이 제공됩니다.
도우미 함수와 일반적으로 이 모듈의 주요 의도는 파이썬 구문(예: 템플릿 엔진)과 긴밀하게 작동하는 라이브러리에 사용하기 쉬운 인터페이스를 제공하는 것입니다.
ast.literal_eval()
eval()은 파이썬의 내장 함수인데, literal_eval은 우리가 하려는 목적을 이루게 하면서도, 안전성까지 보장해주는 함수였다.
더 자세한 내용은 다음을 참조 하자
- 참조에 의하면, 이것은 값을 직접 구문 분석할 필요 없이 신뢰할 수 없는 소스의 Python 값을 포함하는 문자열을 안전하게 평가하는 데 사용할 수 있습니다.
- 예를 들어 연산자 또는 인덱싱과 관련된 임의의 복잡한 표현식을 평가할 수 없습니다.
def literal_eval(node_or_string):
"""
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the following
Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
sets, booleans, and None.
표현식 노드 또는 Python 표현식이 포함된 문자열을 안전하게 평가하십시오.
제공된 문자열 또는 노드는 문자열, 바이트, 숫자, 튜플, 목록, 사전, 집합, 부울 및 없음과 같은
Python 리터럴 구조로만 구성될 수 있습니다.
"""
if isinstance(node_or_string, str):
node_or_string = parse(node_or_string, mode='eval')
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
def _raise_malformed_node(node):
raise ValueError(f'malformed node or string: {node!r}')
def _convert_num(node):
if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
_raise_malformed_node(node)
return node.value
def _convert_signed_num(node):
if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
operand = _convert_num(node.operand)
if isinstance(node.op, UAdd):
return + operand
else:
return - operand
return _convert_num(node)
def _convert(node):
if isinstance(node, Constant):
return node.value
elif isinstance(node, Tuple):
return tuple(map(_convert, node.elts))
elif isinstance(node, List):
return list(map(_convert, node.elts))
elif isinstance(node, Set):
return set(map(_convert, node.elts))
elif (isinstance(node, Call) and isinstance(node.func, Name) and
node.func.id == 'set' and node.args == node.keywords == []):
return set()
elif isinstance(node, Dict):
if len(node.keys) != len(node.values):
_raise_malformed_node(node)
return dict(zip(map(_convert, node.keys),
map(_convert, node.values)))
elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
left = _convert_signed_num(node.left)
right = _convert_num(node.right)
if isinstance(left, (int, float)) and isinstance(right, complex):
if isinstance(node.op, Add):
return left + right
else:
return left - right
return _convert_signed_num(node)
return _convert(node_or_string)
'''
경고:
Python AST 컴파일러의 스택 깊이 제한으로 인해 충분히 크고 복잡한 문자열로 Python 인터프리터가 충돌할 수 있습니다.
잘못된 입력에 따라 ValueError, TypeError, SyntaxError, MemoryError 및 RecursionError가 발생할 수 있습니다.
'''
댓글