อัปเดต dataframe ในนุ่นขณะทำซ้ำทีละแถว


214

ฉันมีกรอบข้อมูลแพนด้าที่มีลักษณะเช่นนี้ (มันค่อนข้างใหญ่)

           date      exer exp     ifor         mat  
1092  2014-03-17  American   M  528.205  2014-04-19 
1093  2014-03-17  American   M  528.205  2014-04-19 
1094  2014-03-17  American   M  528.205  2014-04-19 
1095  2014-03-17  American   M  528.205  2014-04-19    
1096  2014-03-17  American   M  528.205  2014-05-17 

ตอนนี้ฉันต้องการวนซ้ำทีละแถวและเมื่อฉันผ่านแต่ละแถวค่าของifor ในแต่ละแถวสามารถเปลี่ยนแปลงได้ขึ้นอยู่กับเงื่อนไขบางอย่างและฉันต้องการค้นหา dataframe อื่น

ตอนนี้ฉันจะอัปเดตสิ่งนี้อย่างไรเมื่อฉันย้ำ พยายามบางสิ่งที่พวกเขาไม่ได้ทำงาน

for i, row in df.iterrows():
    if <something>:
        row['ifor'] = x
    else:
        row['ifor'] = y

    df.ix[i]['ifor'] = x

วิธีการเหล่านี้ดูเหมือนจะไม่ทำงาน ฉันไม่เห็นค่าที่อัปเดตใน dataframe


2
df.ix[i,'ifor']ฉันคิดว่าคุณต้องการ df.ix[i]['ifor']เป็นปัญหาเนื่องจากเป็นดัชนีที่ถูกล่ามโซ่ (ซึ่งไม่น่าเชื่อถือในนุ่น)
Karl D.

1
คุณสามารถให้กรอบอื่น ๆ <something>เช่นเดียวกับ ไม่ว่าโค้ดของคุณจะเป็นแบบเวกเตอร์จะขึ้นอยู่กับสิ่งเหล่านั้นหรือไม่ iterrowsโดยทั่วไปควรหลีกเลี่ยง ในกรณีของคุณคุณควรแน่นอนหลีกเลี่ยงได้เนื่องจากแต่ละแถวจะเป็นdtypeobject Series
Phillip Cloud

คุณควรสร้างมาสก์บูลีนให้เหมาะกับสภาพของคุณอัพเดทแถวเหล่านั้นทั้งหมดจากนั้นตั้งค่าส่วนที่เหลือเป็นค่าอื่น
EdChum

โปรดอย่าใช้ iterrows () มันเป็นเครื่องมือที่ชัดเจนที่สุดของการต่อต้านแบบที่เลวร้ายที่สุดในประวัติศาสตร์ของแพนด้า
cs95

คำตอบ:


232

คุณสามารถกำหนดค่าในลูปโดยใช้ df.set_value:

for i, row in df.iterrows():
    ifor_val = something
    if <condition>:
        ifor_val = something_else
    df.set_value(i,'ifor',ifor_val)

หากคุณไม่ต้องการค่าแถวคุณสามารถทำซ้ำดัชนีของ df ได้ แต่ฉันเก็บ for-loop ดั้งเดิมไว้ในกรณีที่คุณต้องการค่าแถวสำหรับบางอย่างที่ไม่ได้แสดงไว้ที่นี่

ปรับปรุง

df.set_value () เลิกใช้แล้วตั้งแต่เวอร์ชั่น 0.21.0 คุณสามารถใช้ df.at () แทน:

for i, row in df.iterrows():
    ifor_val = something
    if <condition>:
        ifor_val = something_else
    df.at[i,'ifor'] = ifor_val

6
ดูpandas.pydata.org/pandas-docs/stable/generated/ … , bullet ที่สอง: "2. คุณไม่ควรแก้ไขบางสิ่งที่คุณกำลังทำซ้ำ"
Davor Josipovic

32
ฉันไม่แน่ใจว่าเราอ่านมันเหมือนกันทุกประการ หากคุณดูในรหัสหลอกของฉันฉันทำการแก้ไขใน dataframe ไม่ใช่ค่าจาก iterator ค่าตัววนซ้ำใช้สำหรับดัชนีของค่า / วัตถุเท่านั้น สิ่งที่จะล้มเหลวคือแถว ['ifor'] = some_thing ด้วยเหตุผลที่กล่าวถึงในเอกสารประกอบ
rakke

3
ขอบคุณสำหรับการชี้แจง
Davor Josipovic

8
ตอนนี้ set_value ก็ถูกถอนออกอีกและควรใช้. at (หรือ. ati) ดังนั้นลูปของฉันจะเป็นดังนี้: สำหรับ i, แถวใน df.iterrows (): ifor_val = บางสิ่งถ้า <condition>: ifor_val = something_else df.at [ i, 'ifor'] = ifor_val
complexM

2
set_value เลิกใช้แล้วและจะถูกลบในการเปิดตัวในอนาคต โปรดใช้. at [] หรือ .iat [] accessors แทน
RoyaumeIX

75

วัตถุ Pandas DataFrame ควรถูกพิจารณาเป็น Series of Series กล่าวอีกนัยหนึ่งคุณควรนึกถึงมันในแง่ของคอลัมน์ เหตุผลที่สิ่งนี้สำคัญเนื่องจากเมื่อคุณใช้pd.DataFrame.iterrowsคุณจะวนซ้ำแถวเป็นอนุกรม แต่นี่ไม่ใช่ซีรีย์ที่เฟรมข้อมูลเก็บอยู่และเป็นซีรี่ส์ใหม่ที่สร้างขึ้นสำหรับคุณในขณะที่คุณทำซ้ำ นั่นหมายความว่าเมื่อคุณพยายามที่จะกำหนดสรรพสิ่งเหล่านั้นการแก้ไขเหล่านั้นจะไม่ปรากฏในกรอบข้อมูลดั้งเดิม

ตกลงตอนนี้สิ่งนั้นไม่อยู่: เราจะทำอย่างไร

คำแนะนำก่อนโพสต์นี้รวมถึง:

  1. pd.DataFrame.set_valueจะเลิกเป็นของนุ่นรุ่น 0.21
  2. pd.DataFrame.ixจะเลิก
  3. pd.DataFrame.locไม่เป็นไร แต่สามารถทำงานกับตัวทำดัชนีอาร์เรย์และคุณสามารถทำได้ดีกว่า

คำแนะนำของฉัน
ใช้pd.DataFrame.at

for i in df.index:
    if <something>:
        df.at[i, 'ifor'] = x
    else:
        df.at[i, 'ifor'] = y

คุณสามารถเปลี่ยนเป็น:

for i in df.index:
    df.at[i, 'ifor'] = x if <something> else y

การตอบสนองต่อความคิดเห็น

และถ้าฉันต้องการใช้ค่าของแถวก่อนหน้าสำหรับเงื่อนไข if

for i in range(1, len(df) + 1):
    j = df.columns.get_loc('ifor')
    if <something>:
        df.iat[i - 1, j] = x
    else:
        df.iat[i - 1, j] = y

และถ้าฉันต้องการใช้ค่าของแถวก่อนหน้าสำหรับเงื่อนไข if เพิ่มคอลัมน์ที่ล้าหลังลงใน OG df หรือไม่
Yuca

ประสิทธิภาพอย่างชาญฉลาดวิธีการของคุณดีขึ้นเมื่อเทียบกับการเพิ่มคอลัมน์ที่ล้าหลังหรือมีผลกระทบเล็กน้อยสำหรับชุดข้อมูลขนาดเล็ก (<10k แถว)
Yuca

ขึ้นอยู่กับว่า ฉันจะใช้คอลัมน์ที่ล้าหลัง คำตอบนี้แสดงว่าต้องทำอย่างไรถ้าคุณต้องวนซ้ำ แต่ถ้าคุณไม่ต้องห่วงก็ไม่ต้อง
piRSquared

เข้าใจแล้วถ้าเป็นไปได้ที่จะมีข้อเสนอแนะของคุณสำหรับstackoverflow.com/q/51753001/9754169ก็จะน่ากลัว: D
Yuca

ดีสำหรับการตัดกัน. at [] กับทางเลือกที่เก่ากว่า
Justas

35

วิธีที่คุณสามารถใช้ได้คือitertuples()มันวนซ้ำแถว DataFrame ในชื่อ namedtuples โดยมีค่าดัชนีเป็นองค์ประกอบแรกของ tuple iterrows()และมันจะมากได้เร็วขึ้นมากเมื่อเทียบกับ สำหรับitertuples()แต่ละรายการrowมีอยู่Indexใน DataFrame และคุณสามารถใช้locเพื่อตั้งค่า

for row in df.itertuples():
    if <something>:
        df.at[row.Index, 'ifor'] = x
    else:
        df.at[row.Index, 'ifor'] = x

    df.loc[row.Index, 'ifor'] = x

ภายใต้กรณีส่วนใหญ่itertuples()จะเร็วกว่าหรือiatat

ขอบคุณ @SantiStSupery การใช้.atเร็วกว่าlocมาก


3
เนื่องจากคุณชี้ไปที่ดัชนีที่แม่นยำเท่านั้นคุณอาจคิดถึงการใช้. at แทน. loc เพื่อปรับปรุงประสิทธิภาพของคุณ ดูคำถามนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้
SantiStSupery

แปลกคิด แต่df.loc[row.Index, 3] = xไม่ได้ผล ในทางกลับกันใช้df.loc[row.Index, 'ifor'] = xงานได้!
seralouk

19

คุณควรกำหนดค่าโดยdf.ix[i, 'exp']=Xหรือแทนdf.loc[i, 'exp']=Xdf.ix[i]['ifor'] = x

มิฉะนั้นคุณกำลังทำงานกับมุมมองและควรได้รับความร้อน:

-c:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead

แต่แน่นอนว่าการวนซ้ำน่าจะถูกแทนที่ด้วยอัลกอริทึมแบบเวกเตอร์บางส่วนเพื่อใช้ประโยชน์อย่างเต็มที่DataFrameตามที่ @Phillip Cloud แนะนำ


10

ถ้าคุณจะทำซ้ำอีกทำไมไม่ใช้วิธีที่ง่ายที่สุดของทั้งหมด df['Column'].values[i]

df['Column'] = ''

for i in range(len(df)):
    df['Column'].values[i] = something/update/new_value

หรือถ้าคุณต้องการเปรียบเทียบค่าใหม่กับค่าเก่าหรืออะไรทำนองนั้นทำไมไม่เก็บค่าไว้ในรายการแล้วผนวกท้ายที่สุด

mylist, df['Column'] = [], ''

for <condition>:
    mylist.append(something/update/new_value)

df['Column'] = mylist


0

มันจะดีกว่าที่จะใช้lambdaฟังก์ชั่นโดยใช้df.apply()-

df["ifor"] = df.apply(lambda x: {value} if {condition} else x["ifor"], axis=1)

-3

เพิ่มจำนวน MAX จากคอลัมน์ ตัวอย่างเช่น :

df1 = [sort_ID, Column1,Column2]
print(df1)

ผลลัพธ์ของฉัน:

Sort_ID Column1 Column2
12         a    e
45         b    f
65         c    g
78         d    h

MAX = df1['Sort_ID'].max() #This returns my Max Number 

ตอนนี้ฉันต้องสร้างคอลัมน์ใน df2 และเติมค่าคอลัมน์ที่เพิ่มค่า MAX

Sort_ID Column1 Column2
79      a1       e1
80      b1       f1
81      c1       g1
82      d1       h1

หมายเหตุ: df2 ในขั้นต้นจะมีเฉพาะคอลัมน์ 1 และคอลัมน์ 2 เราต้องการคอลัมน์ Sortid ที่จะสร้างและเพิ่มค่า MAX จาก df1

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.