2016-09-26 15 views
7

Tôi cần trợ giúp chuyển đổi dữ liệu của mình để tôi có thể đọc qua dữ liệu giao dịch.Tạo các nhóm/lớp dựa trên các điều kiện trong các cột

Trường hợp kinh doanh

Tôi đang cố gắng để nhóm lại với nhau một số giao dịch có liên quan để tạo ra một số nhóm hoặc các lớp học của các sự kiện. Tập dữ liệu này đại diện cho những người lao động ra ngoài trên nhiều sự kiện vắng mặt khác nhau. Tôi muốn tạo một lớp lá dựa trên bất kỳ giao dịch nào nằm trong vòng 365 ngày của lớp sự kiện để lại. Đối với các xu hướng biểu đồ, tôi muốn đánh số các lớp để tôi nhận được một chuỗi/mẫu.

Mã của tôi cho phép tôi xem khi nào sự kiện đầu tiên xảy ra và nó có thể xác định khi nào một lớp mới bắt đầu, nhưng nó không xô từng giao dịch vào một lớp.

Yêu cầu:

  • Tag tất cả các hàng dựa trên những gì rời khỏi lớp họ rơi vào.
  • Số từng Sự kiện duy nhất để lại. Sử dụng chỉ số ví dụ 0 này sẽ là Unique Leave Event 2, chỉ mục 1 sẽ là Unique Leave Event 2, chỉ mục 3 sẽ là Unique Leave Event 2, AND index 4 sẽ là Unique Leave Event 1, v.v.

Tôi đã thêm trong một cột cho đầu ra mong muốn, được gắn nhãn là "Đầu ra mong muốn". Lưu ý, có thể có nhiều hàng/sự kiện cho mỗi người; và có thể có nhiều người hơn nữa.

Một số dữ liệu

import pandas as pd 

data = {'Employee ID': ["100", "100", "100","100","200","200","200","300"], 
     'Effective Date': ["2016-01-01","2015-06-05","2014-07-01","2013-01-01","2016-01-01","2015-01-01","2013-01-01","2014-01"], 
     'Desired Output': ["Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 1","Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 1","Unique Leave Event 1"]} 
df = pd.DataFrame(data, columns=['Employee ID','Effective Date','Desired Output']) 

Một số Mã Tôi đã thử

df['Effective Date'] = df['Effective Date'].astype('datetime64[ns]') 
df['EmplidShift'] = df['Employee ID'].shift(-1) 
df['Effdt-Shift'] = df['Effective Date'].shift(-1) 
df['Prior Row in Same Emplid Class'] = "No" 
df['Effdt Diff'] = df['Effdt-Shift'] - df['Effective Date'] 
df['Effdt Diff'] = (pd.to_timedelta(df['Effdt Diff'], unit='d') + pd.to_timedelta(1,unit='s')).astype('timedelta64[D]') 
df['Cumul. Count'] = df.groupby('Employee ID').cumcount() 


df['Groupby'] = df.groupby('Employee ID')['Cumul. Count'].transform('max') 
df['First Row Appears?'] = "" 
df['First Row Appears?'][df['Cumul. Count'] == df['Groupby']] = "First Row" 
df['Prior Row in Same Emplid Class'][ df['Employee ID'] == df['EmplidShift']] = "Yes" 

df['Prior Row in Same Emplid Class'][ df['Employee ID'] == df['EmplidShift']] = "Yes" 

df['Effdt > 1 Yr?'] = ""           
df['Effdt > 1 Yr?'][ ((df['Prior Row in Same Emplid Class'] == "Yes") & (df['Effdt Diff'] < -365)) ] = "Yes" 

df['Unique Leave Event'] = "" 
df['Unique Leave Event'][ (df['Effdt > 1 Yr?'] == "Yes") | (df['First Row Appears?'] == "First Row") ] = "Unique Leave Event" 

df 

Trả lời

2

Bạn có thể thực hiện việc này mà không phải lặp hoặc lặp qua khung dữ liệu của mình. Mỗi Wes McKinney bạn có thể sử dụng .apply() với đối tượng groupBy và xác định hàm để áp dụng cho đối tượng groupby. Nếu bạn sử dụng điều này với .shift() (like here), bạn có thể nhận được kết quả của mình mà không cần sử dụng bất kỳ vòng lặp nào.

dụ ngắn gọn:

# Group by Employee ID 
grouped = df.groupby("Employee ID") 
# Define function 
def get_unique_events(group): 
    # Convert to date and sort by date, like @Khris did 
    group["Effective Date"] = pd.to_datetime(group["Effective Date"]) 
    group = group.sort_values("Effective Date") 
    event_series = (group["Effective Date"] - group["Effective Date"].shift(1) > pd.Timedelta('365 days')).apply(lambda x: int(x)).cumsum()+1 
    return event_series 

event_df = pd.DataFrame(grouped.apply(get_unique_events).rename("Unique Event")).reset_index(level=0) 
df = pd.merge(df, event_df[['Unique Event']], left_index=True, right_index=True) 
df['Output'] = df['Unique Event'].apply(lambda x: "Unique Leave Event " + str(x)) 
df['Match'] = df['Desired Output'] == df['Output'] 

print(df) 

Output:

Employee ID Effective Date  Desired Output Unique Event \ 
3   100  2013-01-01 Unique Leave Event 1    1 
2   100  2014-07-01 Unique Leave Event 2    2 
1   100  2015-06-05 Unique Leave Event 2    2 
0   100  2016-01-01 Unique Leave Event 2    2 
6   200  2013-01-01 Unique Leave Event 1    1 
5   200  2015-01-01 Unique Leave Event 2    2 
4   200  2016-01-01 Unique Leave Event 2    2 
7   300  2014-01 Unique Leave Event 1    1 

       Output Match 
3 Unique Leave Event 1 True 
2 Unique Leave Event 2 True 
1 Unique Leave Event 2 True 
0 Unique Leave Event 2 True 
6 Unique Leave Event 1 True 
5 Unique Leave Event 2 True 
4 Unique Leave Event 2 True 
7 Unique Leave Event 1 True 

dụ More verbose cho rõ ràng:

import pandas as pd 

data = {'Employee ID': ["100", "100", "100","100","200","200","200","300"], 
     'Effective Date': ["2016-01-01","2015-06-05","2014-07-01","2013-01-01","2016-01-01","2015-01-01","2013-01-01","2014-01"], 
     'Desired Output': ["Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 1","Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 1","Unique Leave Event 1"]} 
df = pd.DataFrame(data, columns=['Employee ID','Effective Date','Desired Output']) 

# Group by Employee ID 
grouped = df.groupby("Employee ID") 

# Define a function to get the unique events 
def get_unique_events(group): 
    # Convert to date and sort by date, like @Khris did 
    group["Effective Date"] = pd.to_datetime(group["Effective Date"]) 
    group = group.sort_values("Effective Date") 
    # Define a series of booleans to determine whether the time between dates is over 365 days 
    # Use .shift(1) to look back one row 
    is_year = group["Effective Date"] - group["Effective Date"].shift(1) > pd.Timedelta('365 days') 
    # Convert booleans to integers (0 for False, 1 for True) 
    is_year_int = is_year.apply(lambda x: int(x))  
    # Use the cumulative sum function in pandas to get the cumulative adjustment from the first date. 
    # Add one to start the first event as 1 instead of 0 
    event_series = is_year_int.cumsum() + 1 
    return event_series 

# Run function on df and put results into a new dataframe 
# Convert Employee ID back from an index to a column with .reset_index(level=0) 
event_df = pd.DataFrame(grouped.apply(get_unique_events).rename("Unique Event")).reset_index(level=0) 

# Merge the dataframes 
df = pd.merge(df, event_df[['Unique Event']], left_index=True, right_index=True) 

# Add string to match desired format 
df['Output'] = df['Unique Event'].apply(lambda x: "Unique Leave Event " + str(x)) 

# Check to see if output matches desired output 
df['Match'] = df['Desired Output'] == df['Output'] 

print(df) 

Bạn nhận được kết quả tương tự:

Employee ID Effective Date  Desired Output Unique Event \ 
3   100  2013-01-01 Unique Leave Event 1    1 
2   100  2014-07-01 Unique Leave Event 2    2 
1   100  2015-06-05 Unique Leave Event 2    2 
0   100  2016-01-01 Unique Leave Event 2    2 
6   200  2013-01-01 Unique Leave Event 1    1 
5   200  2015-01-01 Unique Leave Event 2    2 
4   200  2016-01-01 Unique Leave Event 2    2 
7   300  2014-01 Unique Leave Event 1    1 

       Output Match 
3 Unique Leave Event 1 True 
2 Unique Leave Event 2 True 
1 Unique Leave Event 2 True 
0 Unique Leave Event 2 True 
6 Unique Leave Event 1 True 
5 Unique Leave Event 2 True 
4 Unique Leave Event 2 True 
7 Unique Leave Event 1 True 
+0

Đó là một giải pháp thanh lịch. Mối nguy hiểm duy nhất có thể nằm trong 'hợp nhất' nếu OP đang sử dụng các datafram thực sự khổng lồ, nhưng xét theo nội dung của dữ liệu không chắc chắn. – Khris

3

Đây là một chút thời gian nhưng nó mang lại kết quả đúng ít nhất là cho ví dụ nhỏ của bạn:

import pandas as pd 

data = {'Employee ID': ["100", "100", "100","100","200","200","200","300"], 
     'Effective Date': ["2016-01-01","2015-06-05","2014-07-01","2013-01-01","2016-01-01","2015-01-01","2013-01-01","2014-01-01"], 
     'Desired Output': ["Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 1","Unique Leave Event 2","Unique Leave Event 2","Unique Leave Event 1","Unique Leave Event 1"]} 
df = pd.DataFrame(data, columns=['Employee ID','Effective Date','Desired Output']) 

df["Effective Date"] = pd.to_datetime(df["Effective Date"]) 
df = df.sort_values(["Employee ID","Effective Date"]).reset_index(drop=True) 

for i,_ in df.iterrows(): 
    df.ix[0,"Result"] = "Unique Leave Event 1" 
    if i < len(df)-1: 
    if df.ix[i+1,"Employee ID"] == df.ix[i,"Employee ID"]: 
     if df.ix[i+1,"Effective Date"] - df.ix[i,"Effective Date"] > pd.Timedelta('365 days'): 
     df.ix[i+1,"Result"] = "Unique Leave Event " + str(int(df.ix[i,"Result"].split()[-1])+1) 
     else: 
     df.ix[i+1,"Result"] = df.ix[i,"Result"] 
    else: 
     df.ix[i+1,"Result"] = "Unique Leave Event 1" 

Lưu ý mã này giả định rằng hàng đầu tiên luôn chứa chuỗi Unique Leave Event 1.

EDIT: Một số giải thích.

Trước tiên tôi chuyển đổi ngày thành định dạng ngày giờ và sau đó sắp xếp lại khung dữ liệu sao cho ngày cho mỗi ID nhân viên tăng dần.

Sau đó, tôi lặp qua các hàng của khung bằng trình lặp lặp được tích hợp sẵn iterrows. _ trong for i,_ chỉ là một trình giữ chỗ cho biến thứ hai mà tôi không sử dụng vì trình vòng lặp cung cấp cả số hàng và hàng, tôi chỉ cần các số ở đây.

Trong trình vòng lặp, tôi đang so sánh hàng khôn ngoan vì vậy theo mặc định, tôi điền vào hàng đầu tiên bằng tay và sau đó gán cho hàng i+1. Tôi làm như vậy vì tôi biết giá trị của hàng đầu tiên nhưng không phải giá trị của hàng cuối cùng. Sau đó, tôi so sánh hàng i+1 thứ với hàng i -th trong một số if -safeguard vì i+1 sẽ cung cấp lỗi chỉ mục cho lần lặp lại cuối cùng.

Trong vòng lặp đầu tiên tôi kiểm tra xem Employee ID có thay đổi giữa hai hàng hay không. Nếu không thì tôi so sánh ngày của hai hàng và xem chúng có cách nhau hơn 365 ngày không. Nếu đây là trường hợp tôi đọc chuỗi "Unique Leave Event X" từ hàng i -thứ, tăng số một và viết nó trong i+1 -row. Nếu những ngày gần hơn tôi chỉ cần sao chép chuỗi từ hàng trước đó.

Nếu Employee ID thay đổi, mặt khác, tôi chỉ viết "Unique Leave Event 1" để bắt đầu lại.

Lưu ý 1: iterrows() không có tùy chọn để đặt vì vậy tôi không thể lặp lại chỉ trên một tập con.

Lưu ý 2: Luôn lặp lại bằng một trong các trình lặp lặp dựng sẵn và chỉ lặp lại nếu bạn không thể giải quyết được sự cố khác.

Lưu ý 3: Khi gán giá trị trong một lần lặp luôn sử dụng ix, loc hoặc iloc.

+0

Cảm ơn! Bạn có thể vui lòng cung cấp một số bình luận về cách bạn đã làm điều này? – Christopher

+0

Xin chào, và xin lỗi vì đã chờ đợi lâu, tôi chỉ bình luận ở đây từ công việc và chúng tôi đã có một ngày cuối tuần ba ngày. Tôi sẽ thêm một số bình luận ngay bây giờ. – Khris

Các vấn đề liên quan