Pandas 열 내부의 사전 / 목록을 별도의 열로 분할
postgreSQL 데이터베이스에 저장된 데이터가 있습니다. Python2.7을 사용하여이 데이터를 쿼리하고 Pandas DataFrame으로 변환합니다. 그러나이 데이터 프레임의 마지막 열에는 그 안에 값의 사전 (또는 목록?)이 있습니다. DataFrame은 다음과 같습니다.
[1] df
Station ID Pollutants
8809 {"a": "46", "b": "3", "c": "12"}
8810 {"a": "36", "b": "5", "c": "8"}
8811 {"b": "2", "c": "7"}
8812 {"c": "11"}
8813 {"a": "82", "c": "15"}
DataFrame이 다음과 같이 보이도록이 열을 별도의 열로 분할해야합니다.
[2] df2
Station ID a b c
8809 46 3 12
8810 36 5 8
8811 NaN 2 7
8812 NaN NaN 11
8813 82 NaN 15
내가 가진 주요 문제는 목록이 같은 길이가 아니라는 것입니다. 그러나 모든 목록에는 a, b, c의 동일한 3 개 값만 포함됩니다. 그리고 그들은 항상 같은 순서로 나타납니다 (a 첫 번째, b 두 번째, c 세 번째).
다음 코드는 작동하고 내가 원하는 것을 정확하게 반환하는 데 사용되었습니다 (df2).
[3] df
[4] objs = [df, pandas.DataFrame(df['Pollutant Levels'].tolist()).iloc[:, :3]]
[5] df2 = pandas.concat(objs, axis=1).drop('Pollutant Levels', axis=1)
[6] print(df2)
지난주에이 코드를 실행했는데 제대로 작동했습니다. 하지만 이제 내 코드가 깨져서 [4] 행에서이 오류가 발생합니다.
IndexError: out-of-bounds on slice (end)
코드를 변경하지 않았지만 이제 오류가 발생합니다. 나는 이것이 내 방법이 강력하거나 적절하지 않기 때문이라고 생각합니다.
이 목록 열을 별도의 열로 분할하는 방법에 대한 제안이나 지침은 매우 감사하겠습니다!
편집 : 하나의 유니 코드 문자열이기 때문에 .tolist () 및 .apply 메서드가 내 코드에서 작동하지 않는다고 생각합니다.
#My data format
u{'a': '1', 'b': '2', 'c': '3'}
#and not
{u'a': '1', u'b': '2', u'c': '3'}
데이터는이 형식으로 postgreSQL 데이터베이스에서 가져옵니다. 이 문제에 대한 도움이나 아이디어가 있습니까? 유니 코드를 변환하는 방법이 있습니까?
문자열을 실제 dict로 변환하려면 df['Pollutant Levels'].map(eval)
. 그 후, 아래 솔루션을 사용하여 dict를 다른 열로 변환 할 수 있습니다.
작은 예를 사용하여 다음을 사용할 수 있습니다 .apply(pd.Series)
.
In [2]: df = pd.DataFrame({'a':[1,2,3], 'b':[{'c':1}, {'d':3}, {'c':5, 'd':6}]})
In [3]: df
Out[3]:
a b
0 1 {u'c': 1}
1 2 {u'd': 3}
2 3 {u'c': 5, u'd': 6}
In [4]: df['b'].apply(pd.Series)
Out[4]:
c d
0 1.0 NaN
1 NaN 3.0
2 5.0 6.0
나머지 데이터 프레임과 결합하려면 concat
위의 결과와 함께 다른 열 을 사용할 수 있습니다.
In [7]: pd.concat([df.drop(['b'], axis=1), df['b'].apply(pd.Series)], axis=1)
Out[7]:
a c d
0 1 1.0 NaN
1 2 NaN 3.0
2 3 5.0 6.0
Using your code, this also works if I leave out the iloc
part:
In [15]: pd.concat([df.drop('b', axis=1), pd.DataFrame(df['b'].tolist())], axis=1)
Out[15]:
a c d
0 1 1.0 NaN
1 2 NaN 3.0
2 3 5.0 6.0
Try this: The data returned from SQL has to converted into a Dict. or could it be "Pollutant Levels"
is now Pollutants'
StationID Pollutants
0 8809 {"a":"46","b":"3","c":"12"}
1 8810 {"a":"36","b":"5","c":"8"}
2 8811 {"b":"2","c":"7"}
3 8812 {"c":"11"}
4 8813 {"a":"82","c":"15"}
df2["Pollutants"] = df2["Pollutants"].apply(lambda x : dict(eval(x)) )
df3 = df2["Pollutants"].apply(pd.Series )
a b c
0 46 3 12
1 36 5 8
2 NaN 2 7
3 NaN NaN 11
4 82 NaN 15
result = pd.concat([df, df3], axis=1).drop('Pollutants', axis=1)
result
StationID a b c
0 8809 46 3 12
1 8810 36 5 8
2 8811 NaN 2 7
3 8812 NaN NaN 11
4 8813 82 NaN 15
I know the question is quite old, but I got here searching for answers. There is actually a better (and faster) way now of doing this using json_normalize
:
import pandas as pd
from pandas.io.json import json_normalize
df2 = json_normalize(df['Pollutant Levels'])
This avoids costly apply functions...
Merlin's answer is better and super easy, but we don't need a lambda function. The evaluation of dictionary can be safely ignored by either of the following two ways as illustrated below:
Way 1: Two steps
# step 1: convert the `Pollutants` column to Pandas dataframe series
df_pol_ps = data_df['Pollutants'].apply(pd.Series)
df_pol_ps:
a b c
0 46 3 12
1 36 5 8
2 NaN 2 7
3 NaN NaN 11
4 82 NaN 15
# step 2: concat columns `a, b, c` and drop/remove the `Pollutants`
df_final = pd.concat([df, df_pol_ps], axis = 1).drop('Pollutants', axis = 1)
df_final:
StationID a b c
0 8809 46 3 12
1 8810 36 5 8
2 8811 NaN 2 7
3 8812 NaN NaN 11
4 8813 82 NaN 15
Way 2: The above two steps can be combined in one go:
df_final = pd.concat([df, df['Pollutants'].apply(pd.Series)], axis = 1).drop('Pollutants', axis = 1)
df_final:
StationID a b c
0 8809 46 3 12
1 8810 36 5 8
2 8811 NaN 2 7
3 8812 NaN NaN 11
4 8813 82 NaN 15
You can use join
with pop
+ tolist
. Performance is comparable to concat
with drop
+ tolist
, but some may find this syntax cleaner:
res = df.join(pd.DataFrame(df.pop('b').tolist()))
Benchmarking with other methods:
df = pd.DataFrame({'a':[1,2,3], 'b':[{'c':1}, {'d':3}, {'c':5, 'd':6}]})
def joris1(df):
return pd.concat([df.drop('b', axis=1), df['b'].apply(pd.Series)], axis=1)
def joris2(df):
return pd.concat([df.drop('b', axis=1), pd.DataFrame(df['b'].tolist())], axis=1)
def jpp(df):
return df.join(pd.DataFrame(df.pop('b').tolist()))
df = pd.concat([df]*1000, ignore_index=True)
%timeit joris1(df.copy()) # 1.33 s per loop
%timeit joris2(df.copy()) # 7.42 ms per loop
%timeit jpp(df.copy()) # 7.68 ms per loop
I strongly recommend the method extract the column 'Pollutants':
df_pollutants = pd.DataFrame(df['Pollutants'].values.tolist(), index=df.index)
it's much faster than
df_pollutants = df['Pollutants'].apply(pd.Series)
when the size of df is giant.
One line solution is following:
>> df = pd.concat([df['Station ID'], df['Pollutants'].apply(pd.Series)], axis=1)
>> print(df)
Station ID a b c
0 8809 46 3 12
1 8810 36 5 8
2 8811 NaN 2 7
3 8812 NaN NaN 11
4 8813 82 NaN 15
in one line:
df = pd.concat([df['a'], df.b.apply(pd.Series)], axis=1)`
'developer tip' 카테고리의 다른 글
Facebook Graph API, 사용자 이메일을받는 방법? (0) | 2020.09.24 |
---|---|
치명적인 오류 : Visual Studio의 "대상 아키텍처 없음" (0) | 2020.09.24 |
뷰가 좋은 이유는 무엇입니까? (0) | 2020.09.24 |
Bash에서 따옴표로 묶인 문자열에서 줄 바꿈을 어떻게 유지합니까? (0) | 2020.09.24 |
Android TextView에서 HTML의 인라인 이미지를 표시 할 수 있습니까? (0) | 2020.09.24 |