2016-07-06 53 views
21

Tôi có dữ liệu được lưu trong cơ sở dữ liệu postgreSQL. Tôi đang truy vấn dữ liệu này bằng cách sử dụng Python2.7 và biến nó thành một khung dữ liệu Pandas. Tuy nhiên, cột cuối cùng của khung dữ liệu này có một từ điển (hoặc danh sách?) Của các giá trị bên trong nó. Các DataFrame trông như thế này:Tách từ điển/danh sách bên trong một Cột gấu trúc thành các cột riêng biệt

[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"} 

tôi cần phải chia cột này thành các cột riêng biệt để các DataFrame trông như thế này:

[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 

Vấn đề lớn tôi đang gặp là danh sách không cùng độ dài. Nhưng tất cả các danh sách chỉ chứa tối đa 3 giá trị giống nhau: a, b và c. Và chúng luôn xuất hiện theo thứ tự giống nhau (thứ nhất, thứ hai, thứ ba).

Mã sau SỬ DỤNG để hoạt động và trả lại chính xác những gì tôi muốn (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) 

Tôi đã chạy mã này chỉ trong tuần trước và hoạt động tốt. Nhưng bây giờ mã của tôi bị hỏng và tôi nhận được lỗi này từ dòng [4]: ​​

IndexError: out-of-bounds on slice (end) 

Tôi không thay đổi mã nhưng bây giờ nhận được lỗi. Tôi cảm thấy điều này là do phương pháp của tôi không mạnh mẽ hoặc thích hợp.

Bất kỳ đề xuất hoặc hướng dẫn nào về cách tách cột danh sách này thành các cột riêng biệt sẽ được đánh giá cao!

EDIT: Tôi nghĩ rằng ToList() và phương pháp .apply không làm việc trên mã của tôi bởi vì nó là một trong chuỗi unicode, ví dụ:

#My data format 
u{'a': '1', 'b': '2', 'c': '3'} 

#and not 
{u'a': '1', u'b': '2', u'c': '3'} 

Dữ liệu được nhập khẩu từ các cơ sở dữ liệu PostgreSQL ở định dạng này . Bất kỳ trợ giúp hoặc ý tưởng nào về vấn đề này? có cách nào để chuyển đổi unicode?

+0

Tôi đã trả lời với một giải pháp hơi khác nhau, nhưng, mã của bạn nên thực sự cũng chỉ làm việc tốt. Sử dụng ví dụ giả của tôi dưới đây, điều này hoạt động bằng cách sử dụng gấu trúc 0,18,1 nếu tôi bỏ phần 'iloc' – joris

+0

Là một phần của nó mà 'iloc [:,: 3]' giả định sẽ có 3 mục và có thể dữ liệu gần đây hơn lát chỉ có 1 hoặc 2 (ví dụ như không có 'b' như trong' index 8813')? – dwanderson

Trả lời

35

Để chuyển chuỗi thành một dict thực tế, bạn có thể làm df['Pollutant Levels'].map(eval). Sau đó, giải pháp bên dưới có thể được sử dụng để chuyển đổi dict sang các cột khác nhau.


Sử dụng một ví dụ nhỏ, bạn có thể sử dụng .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 

Để kết hợp nó với phần còn lại của dataframe, bạn có thể concat các cột khác với kết quả trên:

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 

Sử dụng mã của bạn, điều này cũng có tác dụng nếu tôi bỏ qua iloc phần:

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 
+2

Tôi đã sử dụng 'pd.DataFrame (df [col] .tolist())' trong một thời gian dài, không bao giờ nghĩ về 'apply (pd.Series)'. Rất đẹp. – ayhan

+0

Tôi hiện đang nhận ra sự cố. .apply (pd.Series) không hoạt động trên tập dữ liệu của tôi vì toàn bộ hàng là một chuỗi unicode. Đó là: u '{' a ':' 1 ',' b ':' 2 ',' c ':' 3 '} và không phải là {u'a': '1', u'b ':' 2 ', u'c ':' 3 '} như các giải pháp của bạn cho thấy. Vì vậy, mã không thể chia thành 3 cột dễ nhận biết. – llaffin

+0

@ayhan Thực ra, đã thử nghiệm nó và phương pháp 'DataFrame (df ['col']. Tolist())' khá nhanh hơn phương pháp áp dụng! – joris

4

Hãy thử điều này: Dữ liệu được trả về từ SQL phải chuyển đổi thành Dict. hoặc nó có thể là "Pollutant Levels" tại 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 
0

là trong một dòng:

df = pd.concat([df['a'], df.b.apply(pd.Series)], axis=1)` 
Các vấn đề liên quan