pandas 有没有办法在Python中将某种格式的字符串转换为 Dataframe

ohtdti5x  于 2023-06-20  发布在  Python
关注(0)|答案(3)|浏览(112)

我有一个字符串,格式如下:

string_1 = '{!Cat1!:{!A!:!xd!# !B!:!yd!# !C!:!zd!# !D!:[!nd!#!nd2!#!nd3!#!nd4!]# !E!:!hd!}#!Cat2!:{!A1!:!xd1!# !B1!:!yd1!# !C1!:!zd1!# !D1!:[!nd1!#!nd21!#!nd31!#!nd41!]# !E1!:!hd1!}}'

我想检查是否有一种方法可以将上面的字符串转换为下面的dataframe:

string_1_to_df
 
Col1 Col2 Col3

Cat1  A    xd
Cat1  B    yd
Cat1  C    zd
Cat1  D    nd
Cat1  D    nd2
Cat1  D    nd3
Cat1  D    nd4
Cat1  E    hd
Cat2  A1   xd1
Cat2  B1   yd1
Cat2  C1   zd1
Cat2  D1   nd1
Cat2  D1   nd21
Cat2  D1   nd31
Cat2  D1   nd41
Cat2  E1   hd1

我试过用密码

new_String = string_1 .replace('!', '"').replace('#', ',')
new_String = json.loads(new_String )
new_String_df = pd.DataFrame.from_dict(new_String)

但我得到的输出是不同的,不是在一个 Dataframe

svmlkihl

svmlkihl1#

json.loads中获取python对象后的下一步是扁平化嵌套数据。有很多方法可以做到这一点,但由于你可能不会使用pandas,dataframe甚至常规的旧python类型的高级方法,因此迭代对象可能是你的家庭作业的正确级别。
您可能需要嵌套几个for循环。举个例子,要从这个嵌套输出中提取dataframe的前两列:

#your existing code
new_String = string_1 .replace('!', '"').replace('#', ',')
new_String = json.loads(new_String)

#iterating through the object to make a list of lists:
flattened = []
for col1 in new_String:
    for col2 in new_String[col1]:
        flattened.append([col1, col2])

要获得第三个元素,可以再次迭代js[col1][col2]。请注意,这一层的复杂性有所增加,因为您有像'A':'xd''D': ['nd', 'nd2', 'nd3', 'nd4']这样的元素,因此您需要确定是否使用strlist类型的字典值并进行适当的迭代。
完成后,您可以使用以下命令推入 Dataframe :

df = pd.DataFrame(flattened, columns=['col1','col2','col3'])
btqmn9zl

btqmn9zl2#

分两个阶段进行:1)字符串解析,2) Dataframe 构造:

import json

d = json.loads(string_1.replace('!', '"').replace('#', ','))
df = (pd.DataFrame.from_dict(d).stack().explode().reset_index()
     .pipe(lambda df: df.set_axis(range(df.shape[1]), axis=1)))
0     1     2
0    A  Cat1    xd
1    B  Cat1    yd
2    C  Cat1    zd
3    D  Cat1    nd
4    D  Cat1   nd2
5    D  Cat1   nd3
6    D  Cat1   nd4
7    E  Cat1    hd
8   A1  Cat2   xd1
9   B1  Cat2   yd1
10  C1  Cat2   zd1
11  D1  Cat2   nd1
12  D1  Cat2  nd21
13  D1  Cat2  nd31
14  D1  Cat2  nd41
15  E1  Cat2   hd1
yc0p9oo0

yc0p9oo03#

请注意,在代码中使用eval()被认为是不好的做法。但是,这里有一个使用它的解决方案:

import pandas as pd

string_1 = '{!Cat1!:{!A!:!xd!# !B!:!yd!# !C!:!zd!# !D!:[!nd!#!nd2!#!nd3!#!nd4!]# !E!:!hd!}#!Cat2!:{!A1!:!xd1!# !B1!:!yd1!# !C1!:!zd1!# !D1!:[!nd1!#!nd21!#!nd31!#!nd41!]# !E1!:!hd1!}}'

d = eval(string_1.replace("!", "'").replace("#", ','))
cols = ['Col1', 'Col2', 'Col3']
df = {col: [] for col in cols}
for k, v in d.items():
    for k2, v2 in v.items():
        if isinstance(v2, list):
            for j in v2:
                for col, v in zip(cols, [k, k2, j]):
                    df[col].append(v)
        else:
            for col, v in zip(cols, [k, k2, v2]):
                df[col].append(v)
                
string_to_df = pd.DataFrame(df)
print(string_to_df)

输出:

Col1 Col2  Col3
0   Cat1    A    xd
1   Cat1    B    yd
2   Cat1    C    zd
3   Cat1    D    nd
4   Cat1    D   nd2
5   Cat1    D   nd3
6   Cat1    D   nd4
7   Cat1    E    hd
8   Cat2   A1   xd1
9   Cat2   B1   yd1
10  Cat2   C1   zd1
11  Cat2   D1   nd1
12  Cat2   D1  nd21
13  Cat2   D1  nd31
14  Cat2   D1  nd41
15  Cat2   E1   hd1

理想情况下,你应该使用正则表达式,所以我会弄清楚这一点,并很快更新这篇文章。

相关问题